Send email using boost asio

4.2k views Asked by At

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...

0

There are 0 answers