2nd update: Now the server says: "Ready to start TLS", how to modify my code to perform this TLS negotiation?
I am trying to use boost asio to send an email from one account to another, but failing.
#include <istream>
#include <ostream>
#include <string>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/archive/iterators/base64_from_binary.hpp>
#include <boost/archive/iterators/transform_width.hpp>
#include <boost/archive/iterators/ostream_iterator.hpp>
using namespace boost::archive::iterators;
typedef base64_from_binary<transform_width<const char *,6,8> > base64_text;
class SMTPClient
{
public:
SMTPClient(std::string pServer,unsigned int pPort,std::string pUser,std::string pPassword): mServer(pServer),mPort(pPort),mUserName(pUser),mPassword(pPassword),mSocket(mIOService),mResolver(mIOService)
{
tcp::resolver::query qry(mServer,boost::lexical_cast<std::string>( mPort ));
mResolver.async_resolve(qry,boost::bind(&SMTPClient::handleResolve,this,boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
}
bool Send(std::string pFrom,std::string pTo,std::string pSubject,std::string pMessage, string &error)
{
mFrom=pFrom;
mTo=pTo;
mSubject=pSubject;
mMessage=pMessage;
mIOService.run();
error = mErrorMsg;
return mHasError;
}
private:
std::string encodeBase64(std::string pData)
{
std::stringstream os;
size_t sz=pData.size();
std::copy(base64_text(pData.c_str()),base64_text(pData.c_str()+sz),std::ostream_iterator<char>(os));
return os.str();
}
void handleResolve(const boost::system::error_code& err,tcp::resolver::iterator endpoint_iterator)
{
if(!err)
{
tcp::endpoint endpoint=*endpoint_iterator;
mSocket.async_connect(endpoint,
boost::bind(&SMTPClient::handleConnect,this,boost::asio::placeholders::error,++endpoint_iterator));
}
else
{
mHasError=true;
mErrorMsg= err.message();
}
}
void writeLine(std::string pData)
{
std::ostream req_strm(&mRequest);
req_strm << pData << "\r\n";
boost::asio::write(mSocket,mRequest);
req_strm.clear();
}
void handleConnect(const boost::system::error_code& err,tcp::resolver::iterator endpoint_iterator)
{
if (!err)
{// The connection was successful. Send the request.
std::ostream req_strm(&mRequest);
writeLine("EHLO "+mServer);
writeLine("STARTTLS");
writeLine(encodeBase64(mUserName));
writeLine(encodeBase64(mPassword));
writeLine( "MAIL FROM:<"+mFrom+">");
writeLine( "RCPT TO:<"+mTo+">");
writeLine( "DATA");
writeLine( "SUBJECT:"+mSubject);
writeLine( "From:"+mFrom);
writeLine( "To:"+mTo);
writeLine( "");
writeLine( mMessage );
writeLine( ".\r\n");
}
else
{
mHasError=true;
mErrorMsg= err.message();
}
size_t s = -1;
while(s > 0 || s == -1)
{
const int max_length = 4096;
char data[max_length];
boost::system::error_code error;
s = mSocket.read_some(boost::asio::buffer(data), error);
if(s > 0)
{
char d[4096];
strncpy(d, data, s);
d[s] = '\0';
cout << d;
}
}
}
std::string mServer;
std::string mUserName;
std::string mPassword;
std::string mFrom;
std::string mTo;
std::string mSubject;
std::string mMessage;
unsigned int mPort;
boost::asio::io_service mIOService;
tcp::resolver mResolver;
tcp::socket mSocket;
boost::asio::streambuf mRequest;
boost::asio::streambuf mResponse;
bool mHasError;
std::string mErrorMsg;
};
bool send_mail(string text, string &error)
{
string
subject = "Subject",
me_mail = "[email protected]",
me_mail_server = "smtp.gmail.com",
me_user = "[email protected]",
me_pass = "xxx_pass",
target_mail = "[email protected]";
int server_port = 587;
SMTPClient mailc(me_mail_server, server_port, me_user, me_pass);
return mailc.Send(me_mail, target_mail, subject, text, error);
}
Can you please help me? I am not experienced about the smtp protocol, so I found this difficult...