Process header before transmitting message via SMTP.
This commit is contained in:
parent
d8b3d2b641
commit
e3bb8020e0
@ -674,6 +674,13 @@ void body::setParentPart(ref <bodyPart> parent)
|
|||||||
{
|
{
|
||||||
m_part = parent;
|
m_part = parent;
|
||||||
m_header = (parent != NULL ? parent->getHeader() : NULL);
|
m_header = (parent != NULL ? parent->getHeader() : NULL);
|
||||||
|
|
||||||
|
for (std::vector <ref <bodyPart> >::iterator it = m_parts.begin() ;
|
||||||
|
it != m_parts.end() ; ++it)
|
||||||
|
{
|
||||||
|
ref <bodyPart> childPart = *it;
|
||||||
|
childPart->m_parent = parent;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,6 +121,12 @@ ref <header> bodyPart::getHeader()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bodyPart::setHeader(ref <header> h)
|
||||||
|
{
|
||||||
|
m_header = h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const ref <const body> bodyPart::getBody() const
|
const ref <const body> bodyPart::getBody() const
|
||||||
{
|
{
|
||||||
return (m_body);
|
return (m_body);
|
||||||
@ -133,6 +139,19 @@ ref <body> bodyPart::getBody()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void bodyPart::setBody(ref <body> b)
|
||||||
|
{
|
||||||
|
ref <bodyPart> oldPart = b->m_part.acquire();
|
||||||
|
|
||||||
|
m_body = b;
|
||||||
|
m_body->setParentPart(thisRef().dynamicCast <bodyPart>());
|
||||||
|
|
||||||
|
// A body is associated to one and only one part
|
||||||
|
if (oldPart != NULL)
|
||||||
|
oldPart->setBody(vmime::create <body>());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
ref <bodyPart> bodyPart::getParentPart()
|
ref <bodyPart> bodyPart::getParentPart()
|
||||||
{
|
{
|
||||||
return m_parent.acquire();
|
return m_parent.acquire();
|
||||||
|
@ -32,6 +32,8 @@
|
|||||||
#include "vmime/utility/stream.hpp"
|
#include "vmime/utility/stream.hpp"
|
||||||
#include "vmime/mailboxList.hpp"
|
#include "vmime/mailboxList.hpp"
|
||||||
#include "vmime/message.hpp"
|
#include "vmime/message.hpp"
|
||||||
|
#include "vmime/datetime.hpp"
|
||||||
|
#include "vmime/messageId.hpp"
|
||||||
|
|
||||||
#include "vmime/utility/outputStreamAdapter.hpp"
|
#include "vmime/utility/outputStreamAdapter.hpp"
|
||||||
#include "vmime/utility/inputStreamStringAdapter.hpp"
|
#include "vmime/utility/inputStreamStringAdapter.hpp"
|
||||||
@ -47,6 +49,66 @@ transport::transport(ref <session> sess, const serviceInfos& infos, ref <securit
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
ref <headerField> transport::processHeaderField(ref <headerField> field)
|
||||||
|
{
|
||||||
|
if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::BCC))
|
||||||
|
{
|
||||||
|
// Remove Bcc headers from the message, as required by the RFC.
|
||||||
|
// Some SMTP server automatically strip this header (Postfix, qmail),
|
||||||
|
// and others have an option for this (Exim).
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::RETURN_PATH))
|
||||||
|
{
|
||||||
|
// RFC-2821: Return-Path header is added by the final transport system
|
||||||
|
// that delivers the message to its recipient. Then, it should not be
|
||||||
|
// transmitted to MSA.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
else if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::ORIGINAL_RECIPIENT))
|
||||||
|
{
|
||||||
|
// RFC-2298: Delivering MTA may add the Original-Recipient header and
|
||||||
|
// discard existing one; so, no need to send it.
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Leave the header field as is
|
||||||
|
return field;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void transport::processHeader(ref <header> header)
|
||||||
|
{
|
||||||
|
if (header->getFieldCount() == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Remove/replace fields
|
||||||
|
for (size_t idx = header->getFieldCount() ; idx != 0 ; --idx)
|
||||||
|
{
|
||||||
|
ref <headerField> field = header->getFieldAt(idx - 1);
|
||||||
|
ref <headerField> newField = processHeaderField(field);
|
||||||
|
|
||||||
|
if (newField == NULL)
|
||||||
|
header->removeField(field);
|
||||||
|
else if (newField != field)
|
||||||
|
header->replaceField(field, newField);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add missing header fields
|
||||||
|
// -- Date
|
||||||
|
if (!header->hasField(fields::DATE))
|
||||||
|
header->Date()->setValue(datetime::now());
|
||||||
|
|
||||||
|
// -- Mime-Version
|
||||||
|
if (!header->hasField(fields::MIME_VERSION))
|
||||||
|
header->MimeVersion()->setValue(string(SUPPORTED_MIME_VERSION));
|
||||||
|
|
||||||
|
// -- Message-Id
|
||||||
|
if (!header->hasField(fields::MESSAGE_ID))
|
||||||
|
header->MessageId()->setValue(messageId::generateId());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static void extractMailboxes
|
static void extractMailboxes
|
||||||
(mailboxList& recipients, const addressList& list)
|
(mailboxList& recipients, const addressList& list)
|
||||||
{
|
{
|
||||||
@ -107,15 +169,36 @@ void transport::send(ref <vmime::message> msg, utility::progressListener* progre
|
|||||||
}
|
}
|
||||||
catch (exceptions::no_such_field&) { }
|
catch (exceptions::no_such_field&) { }
|
||||||
|
|
||||||
// Remove BCC headers from the message we're about to send, as required by the RFC.
|
// Process message header by removing fields that should be removed
|
||||||
// Some SMTP server automatically strip this header (Postfix, qmail), and others
|
// before transmitting the message to MSA, and adding missing fields
|
||||||
// have an option for this (Exim).
|
// which are required/recommended by the RFCs.
|
||||||
try
|
ref <header> hdr = msg->getHeader()->clone().dynamicCast <header>();
|
||||||
|
processHeader(hdr);
|
||||||
|
|
||||||
|
// To avoid cloning message body (too much overhead), use processed
|
||||||
|
// header during the time we are generating the message to a stream.
|
||||||
|
// Revert it back to original header after.
|
||||||
|
struct XChangeMsgHeader
|
||||||
{
|
{
|
||||||
ref <headerField> bcc = msg->getHeader()->findField(fields::BCC);
|
XChangeMsgHeader(vmime::ref <vmime::message> _msg,
|
||||||
msg->getHeader()->removeField(bcc);
|
vmime::ref <vmime::header> _hdr)
|
||||||
}
|
: msg(_msg), hdr(msg->getHeader())
|
||||||
catch (exceptions::no_such_field&) { }
|
{
|
||||||
|
// Set new header
|
||||||
|
msg->setHeader(_hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
~XChangeMsgHeader()
|
||||||
|
{
|
||||||
|
// Revert original header
|
||||||
|
msg->setHeader(hdr);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
|
||||||
|
vmime::ref <vmime::message> msg;
|
||||||
|
vmime::ref <vmime::header> hdr;
|
||||||
|
} headerExchanger(msg, hdr);
|
||||||
|
|
||||||
// Generate the message, "stream" it and delegate the sending
|
// Generate the message, "stream" it and delegate the sending
|
||||||
// to the generic send() function.
|
// to the generic send() function.
|
||||||
|
@ -60,6 +60,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
ref <header> getHeader();
|
ref <header> getHeader();
|
||||||
|
|
||||||
|
/** Replaces the header section of this part.
|
||||||
|
*
|
||||||
|
* @param header the new header of this part
|
||||||
|
*/
|
||||||
|
void setHeader(ref <header> header);
|
||||||
|
|
||||||
/** Return the body section of this part.
|
/** Return the body section of this part.
|
||||||
*
|
*
|
||||||
* @return body section
|
* @return body section
|
||||||
@ -72,6 +78,12 @@ public:
|
|||||||
*/
|
*/
|
||||||
ref <body> getBody();
|
ref <body> getBody();
|
||||||
|
|
||||||
|
/** Replaces the body section of this part.
|
||||||
|
*
|
||||||
|
* @param body new body section
|
||||||
|
*/
|
||||||
|
void setBody(ref <body> body);
|
||||||
|
|
||||||
/** Return the parent part of this part.
|
/** Return the parent part of this part.
|
||||||
*
|
*
|
||||||
* @return parent part or NULL if not known
|
* @return parent part or NULL if not known
|
||||||
|
@ -39,6 +39,8 @@
|
|||||||
|
|
||||||
namespace vmime {
|
namespace vmime {
|
||||||
|
|
||||||
|
class header;
|
||||||
|
class headerField;
|
||||||
class message;
|
class message;
|
||||||
class mailbox;
|
class mailbox;
|
||||||
class mailboxList;
|
class mailboxList;
|
||||||
@ -77,6 +79,26 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
Type getType() const;
|
Type getType() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
/** Called by processHeader().
|
||||||
|
* Decides what to do with the specified header field.
|
||||||
|
*
|
||||||
|
* @return NULL if the header should be removed, a reference to a new headerField
|
||||||
|
* if the field is to be replaced, or a reference to the same headerField
|
||||||
|
* that was passed if the field should be left as is
|
||||||
|
*/
|
||||||
|
ref <headerField> processHeaderField(ref <headerField> field);
|
||||||
|
|
||||||
|
/** Prepares the header before transmitting the message.
|
||||||
|
* Removes headers that should not be present (eg. "Bcc", "Return-Path"),
|
||||||
|
* or adds missing headers that are required/recommended by the RFCs.
|
||||||
|
* The header is modified inline.
|
||||||
|
*
|
||||||
|
* @param header headers to process
|
||||||
|
*/
|
||||||
|
void processHeader(ref <header> header);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user