SF #3538785: SMTPClientSession::sendMessage() should take recipient list

This commit is contained in:
Aleksandar Fabijanic 2012-07-23 04:32:26 +00:00
parent 0466c67ff2
commit d56a7a1ee6
7 changed files with 212 additions and 9 deletions

View File

@ -21,6 +21,7 @@ Release 1.5.0 (2012-07-30)
- IPAddress bitwise operators (&,|,^,~)
- IPAddress BinaryReader/Writer << and >> operators
- IPAddress force IPv6 always lowercase (RFC 5952)
- fixed SF#3538785: SMTPClientSession::sendMessage() should take recipient list
Release 1.4.4 (2012-07-??)
==========================

View File

@ -69,7 +69,7 @@ class Net_API MailMessage: public MessageHeader
/// encodings are supported: 7bit, 8bit, quoted-printable
/// and base64.
{
public:
public:
typedef std::vector<MailRecipient> Recipients;
enum ContentDisposition
@ -94,6 +94,9 @@ public:
void addRecipient(const MailRecipient& recipient);
/// Adds a recipient for the message.
void setRecipients(const Recipients& recipient);
/// Clears existing and sets new recipient list for the message.
const Recipients& recipients() const;
/// Returns the recipients of the message.

View File

@ -59,6 +59,8 @@ class Net_API SMTPClientSession
/// client for sending e-mail messages.
{
public:
typedef std::vector<std::string> Recipients;
enum
{
SMTP_PORT = 25
@ -130,7 +132,18 @@ public:
void sendMessage(const MailMessage& message);
/// Sends the given mail message by sending a MAIL FROM command,
/// a RCPT TO command for every recipient, and a DATA command with
/// the message headers and content.
/// the message headers and content. Using this function results in
/// RCPT TO commands list generated from the recipient list supplied
/// with the message itself.
///
/// Throws a SMTPException in case of a SMTP-specific error, or a
/// NetException in case of a general network communication failure.
void sendMessage(const MailMessage& message, const Recipients& recipients);
/// Sends the given mail message by sending a MAIL FROM command,
/// a RCPT TO command for every recipient, and a DATA command with
/// the message headers and content. Using this function results in
/// message header being generated from the supplied recipients list.
///
/// Throws a SMTPException in case of a SMTP-specific error, or a
/// NetException in case of a general network communication failure.
@ -176,6 +189,9 @@ protected:
DialogSocket& socket();
private:
void sendCommands(const MailMessage& message, const Recipients* pRecipients = 0);
void transportMessage(const MailMessage& message);
DialogSocket _socket;
bool _isOpen;
};

View File

@ -133,6 +133,12 @@ void MailMessage::addRecipient(const MailRecipient& recipient)
}
void MailMessage::setRecipients(const Recipients& recipients)
{
_recipients.assign(recipients.begin(), recipients.end());
}
void MailMessage::setSender(const std::string& sender)
{
set(HEADER_FROM, sender);

View File

@ -318,7 +318,7 @@ void SMTPClientSession::close()
}
void SMTPClientSession::sendMessage(const MailMessage& message)
void SMTPClientSession::sendCommands(const MailMessage& message, const Recipients* pRecipients)
{
std::string response;
int status = 0;
@ -335,17 +335,55 @@ void SMTPClientSession::sendMessage(const MailMessage& message)
{
status = sendCommand("MAIL FROM:", fromField.substr(emailPos, fromField.size() - emailPos), response);
}
if (!isPositiveCompletion(status)) throw SMTPException("Cannot send message", response, status);
for (MailMessage::Recipients::const_iterator it = message.recipients().begin(); it != message.recipients().end(); ++it)
std::ostringstream recipient;
if (pRecipients)
{
std::string recipient("<");
recipient.append(it->getAddress());
recipient.append(">");
int status = sendCommand("RCPT TO:", recipient, response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient, response, status);
for (Recipients::const_iterator it = pRecipients->begin(); it != pRecipients->end(); ++it)
{
recipient << '<' << *it << '>';
int status = sendCommand("RCPT TO:", recipient.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient.str(), response, status);
recipient.str("");
}
}
else
{
for (MailMessage::Recipients::const_iterator it = message.recipients().begin(); it != message.recipients().end(); ++it)
{
recipient << '<' << it->getAddress() << '>';
int status = sendCommand("RCPT TO:", recipient.str(), response);
if (!isPositiveCompletion(status)) throw SMTPException(std::string("Recipient rejected: ") + recipient.str(), response, status);
recipient.str("");
}
}
status = sendCommand("DATA", response);
if (!isPositiveIntermediate(status)) throw SMTPException("Cannot send message data", response, status);
}
void SMTPClientSession::sendMessage(const MailMessage& message)
{
sendCommands(message);
transportMessage(message);
}
void SMTPClientSession::sendMessage(const MailMessage& message, const Recipients& recipients)
{
sendCommands(message, &recipients);
transportMessage(message);
}
void SMTPClientSession::transportMessage(const MailMessage& message)
{
std::string response;
int status = 0;
SocketOutputStream socketStream(_socket);
MailOutputStream mailStream(socketStream);
message.write(mailStream);

View File

@ -160,6 +160,141 @@ void SMTPClientSessionTest::testSend()
}
void SMTPClientSessionTest::testSendMultiRecipient()
{
DialogServer server;
server.addResponse("220 localhost SMTP ready");
server.addResponse("250 Hello localhost");
server.addResponse("250 OK");
server.addResponse("250 OK");
server.addResponse("250 OK");
server.addResponse("250 OK");
server.addResponse("354 Send data");
server.addResponse("250 OK");
server.addResponse("250 OK");
server.addResponse("221 Bye");
SMTPClientSession session("localhost", server.port());
session.login("localhost");
MailMessage message;
message.setSender("john.doe@no.where");
MailMessage::Recipients msgRecipients;
msgRecipients.push_back(MailRecipient(MailRecipient::PRIMARY_RECIPIENT, "jane.doe@no.where", "Jane Doe"));
msgRecipients.push_back(MailRecipient(MailRecipient::CC_RECIPIENT, "jack.doe@no.where", "Jack Doe"));
msgRecipients.push_back(MailRecipient(MailRecipient::BCC_RECIPIENT, "joe.doe@no.where", "Joe Doe"));
message.setRecipients(msgRecipients);
message.setSubject("Test Message");
message.setContent("Hello\r\nblah blah\r\n\r\nJohn\r\n");
server.clearCommands();
session.sendMessage(message);
std::string cmd = server.popCommandWait();
assert (cmd == "MAIL FROM: <john.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "RCPT TO: <jane.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "RCPT TO: <jack.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "RCPT TO: <joe.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "DATA");
cmd = server.popCommandWait();
assert (cmd == "CC: Jack Doe <jack.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "Content-Transfer-Encoding: quoted-printable");
cmd = server.popCommandWait();
assert (cmd == "Content-Type: text/plain");
cmd = server.popCommandWait();
assert (cmd.substr(0, 4) == "Date");
cmd = server.popCommandWait();
assert (cmd == "From: john.doe@no.where");
cmd = server.popCommandWait();
assert (cmd == "Subject: Test Message");
cmd = server.popCommandWait();
assert (cmd == "To: Jane Doe <jane.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "Hello");
cmd = server.popCommandWait();
assert (cmd == "blah blah");
cmd = server.popCommandWait();
assert (cmd == "John");
cmd = server.popCommandWait();
assert (cmd == ".");
session.close();
}
void SMTPClientSessionTest::testMultiSeparateRecipient()
{
DialogServer server;
server.addResponse("220 localhost SMTP ready");
server.addResponse("250 Hello localhost");
server.addResponse("250 OK");
server.addResponse("250 OK");
server.addResponse("250 OK");
server.addResponse("250 OK");
server.addResponse("354 Send data");
server.addResponse("250 OK");
server.addResponse("250 OK");
server.addResponse("221 Bye");
SMTPClientSession session("localhost", server.port());
session.login("localhost");
MailMessage message;
message.setSender("john.doe@no.where");
MailMessage::Recipients msgRecipients;
msgRecipients.push_back(MailRecipient(MailRecipient::PRIMARY_RECIPIENT, "jane.doe@no.where", "Jane Doe"));
msgRecipients.push_back(MailRecipient(MailRecipient::CC_RECIPIENT, "jack.doe@no.where", "Jack Doe"));
msgRecipients.push_back(MailRecipient(MailRecipient::CC_RECIPIENT, "joe.doe@no.where", "Joe Doe"));
message.setRecipients(msgRecipients);
message.setSubject("Test Message");
message.setContent("Hello\r\nblah blah\r\n\r\nJohn\r\n");
SMTPClientSession::Recipients recipients;
recipients.push_back("jill.doe@no.where");
recipients.push_back("josh.doe@no.where");
recipients.push_back("jake.doe@no.where");
server.clearCommands();
session.sendMessage(message, recipients);
std::string cmd = server.popCommandWait();
assert (cmd == "MAIL FROM: <john.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "RCPT TO: <jill.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "RCPT TO: <josh.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "RCPT TO: <jake.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "DATA");
cmd = server.popCommandWait();
assert (cmd == "CC: Jack Doe <jack.doe@no.where>, Joe Doe <joe.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "Content-Transfer-Encoding: quoted-printable");
cmd = server.popCommandWait();
assert (cmd == "Content-Type: text/plain");
cmd = server.popCommandWait();
assert (cmd.substr(0, 4) == "Date");
cmd = server.popCommandWait();
assert (cmd == "From: john.doe@no.where");
cmd = server.popCommandWait();
assert (cmd == "Subject: Test Message");
cmd = server.popCommandWait();
assert (cmd == "To: Jane Doe <jane.doe@no.where>");
cmd = server.popCommandWait();
assert (cmd == "Hello");
cmd = server.popCommandWait();
assert (cmd == "blah blah");
cmd = server.popCommandWait();
assert (cmd == "John");
cmd = server.popCommandWait();
assert (cmd == ".");
session.close();
}
void SMTPClientSessionTest::testSendFailed()
{
DialogServer server;
@ -210,6 +345,8 @@ CppUnit::Test* SMTPClientSessionTest::suite()
CppUnit_addTest(pSuite, SMTPClientSessionTest, testLoginHELO);
CppUnit_addTest(pSuite, SMTPClientSessionTest, testLoginFailed);
CppUnit_addTest(pSuite, SMTPClientSessionTest, testSend);
CppUnit_addTest(pSuite, SMTPClientSessionTest, testSendMultiRecipient);
CppUnit_addTest(pSuite, SMTPClientSessionTest, testMultiSeparateRecipient);
CppUnit_addTest(pSuite, SMTPClientSessionTest, testSendFailed);
return pSuite;

View File

@ -50,6 +50,8 @@ public:
void testLoginHELO();
void testLoginFailed();
void testSend();
void testSendMultiRecipient();
void testMultiSeparateRecipient();
void testSendFailed();
void setUp();