Process header before transmitting message via SMTP.

This commit is contained in:
Vincent Richard 2013-02-18 22:00:29 +01:00
parent d8b3d2b641
commit e3bb8020e0
5 changed files with 151 additions and 8 deletions

View File

@ -674,6 +674,13 @@ void body::setParentPart(ref <bodyPart> parent)
{
m_part = parent;
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;
}
}

View File

@ -121,6 +121,12 @@ ref <header> bodyPart::getHeader()
}
void bodyPart::setHeader(ref <header> h)
{
m_header = h;
}
const ref <const body> bodyPart::getBody() const
{
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()
{
return m_parent.acquire();

View File

@ -32,6 +32,8 @@
#include "vmime/utility/stream.hpp"
#include "vmime/mailboxList.hpp"
#include "vmime/message.hpp"
#include "vmime/datetime.hpp"
#include "vmime/messageId.hpp"
#include "vmime/utility/outputStreamAdapter.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
(mailboxList& recipients, const addressList& list)
{
@ -107,15 +169,36 @@ void transport::send(ref <vmime::message> msg, utility::progressListener* progre
}
catch (exceptions::no_such_field&) { }
// Remove BCC headers from the message we're about to send, as required by the RFC.
// Some SMTP server automatically strip this header (Postfix, qmail), and others
// have an option for this (Exim).
try
// Process message header by removing fields that should be removed
// before transmitting the message to MSA, and adding missing fields
// which are required/recommended by the RFCs.
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);
msg->getHeader()->removeField(bcc);
}
catch (exceptions::no_such_field&) { }
XChangeMsgHeader(vmime::ref <vmime::message> _msg,
vmime::ref <vmime::header> _hdr)
: msg(_msg), hdr(msg->getHeader())
{
// 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
// to the generic send() function.

View File

@ -60,6 +60,12 @@ public:
*/
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 body section
@ -72,6 +78,12 @@ public:
*/
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 parent part or NULL if not known

View File

@ -39,6 +39,8 @@
namespace vmime {
class header;
class headerField;
class message;
class mailbox;
class mailboxList;
@ -77,6 +79,26 @@ public:
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);
};