smtp version:2

来源:互联网 发布:涉密检查软件 编辑:程序博客网 时间:2024/06/07 10:13

重新实现了一下smtp,加入一些错误检查,可以发送附件.


头文件:

#ifndef SMTP_H#define SMTP_H#include<iostream>#include<utility>#include<stdexcept>#include<sstream>#include"boost/asio.hpp"#include"boost/format.hpp"#include<boost/algorithm/string.hpp>#include"logging.h"#include"MIME/base64.h"namespace email {using namespace std;using namespace boost;using namespace boost::asio;using namespace logging;#define CR "\r"#define LF "\n"#define CRLF "\r\n"class smtp{    typedef pair<int, string> response;public:    void test();    smtp(io_service& i,const string host, const string port = "smtp");    ~smtp();    void Set_DebugLevel(bool value);    response Quit();    response Noop();    response Helo(const string username);    response Ehlo(const string username);    response Login(const string username,const string password);    response SendMail(const string from_addr,                      const list<string> to_addrs_list,                      const string msg);    response SendMail(const string from_addr,                      const list<string> to_addrs_list,                      istream& input);private:    string _Host;    string _Port;    string _Myaddr;    bool _DebugLevel;    io_service& _Serivce;    ip::tcp::socket _Sock;    asio::streambuf _Streambuf;    response Connect();    string Get_Line();    response Get_Reply();    void Put_Cmd(const string cmd, const string endline = CRLF);    response Do_Cmd(string const cmd);    response Data(const string msg);};}#endif // SMTP_H

实现:

#include "smtp.h"namespace email {smtp::smtp(io_service &i, const string host, const string port)    :_Serivce(i),_Sock(i){    _Host = host;    _Port = port;    response rsp = Connect ();    if (rsp.first != 220)        throw std::runtime_error("Connect error");    if (_DebugLevel)        logger().debug ("Connect succeed");}smtp::~smtp (){    Quit();}smtp::response smtp::Connect(){    /*     * 迭代测试服务器     */    ip::tcp::resolver Rsv(_Serivce);    ip::tcp::resolver::query query(_Host, _Port);    ip::tcp::resolver::iterator Iter;    ip::tcp::resolver::iterator EndIter;    boost::system::error_code err;    for(Iter = Rsv.resolve(query); Iter != EndIter; ++Iter){        _Sock.connect (*Iter,err);        if (!err)            break;        _Sock.close ();    }    if(err)        throw runtime_error("Connect error");    return Get_Reply();}void smtp::Set_DebugLevel(bool value){    /*     * 设置调试级别     */    _DebugLevel = value;}smtp::response smtp::Quit (){    return Do_Cmd ("QUIT");}smtp::response smtp::Noop (){    return Do_Cmd ("NOOP");}smtp::response smtp::Helo (const string username){    auto resp = Do_Cmd ("HELO " + username);    if (resp.first != 250)        throw runtime_error("HELO error");    return resp;}smtp::response smtp::Ehlo (const string username){    auto resp = Do_Cmd ("EHLO " +username);    if (resp.first != 250)        return resp;    logger().info (resp.second);    return resp;}smtp::response smtp::Login (const string username, const string password){    auto reply = Ehlo (username);    if (!contains(reply.second,"AUTH LOGIN"))        throw std::runtime_error("AUTH LOGIN:nonsupport");    reply = Do_Cmd ("AUTH LOGIN");    if (reply.first != 334)        throw std::runtime_error("AUTH LOGIN error:");    reply = Do_Cmd(encode_base64 (username));    if (reply.first != 334)        throw std::runtime_error("AUTH LOGIN error:");    reply = Do_Cmd(encode_base64 (password));    if (reply.first != 235 && reply.first != 503)        /*         * 235 == 'Authentication successful'         * 503 == 'Error: already authenticated'         */        throw std::runtime_error("AUTH LOGIN error:");    _Myaddr = username;    return reply;}smtp::responsesmtp::SendMail (const string from_addr, const list<string> to_addrs_list, const string msg){    /*     *mail FROM: 开始*    */    auto reply =  Do_Cmd (str(format("mail FROM:<%s") % from_addr));    if (reply.first != 250)        if (reply.first == 412)            throw std::runtime_error("rcpt TO error: SMTPSenderRefused");    /*     * mail FROM: 成功,rcpt TO:开始     */    for (auto iter = to_addrs_list.begin (); iter != to_addrs_list.end (); ++iter){        reply = Do_Cmd (str(format("rcpt TO:<%s>") % *iter));        if (reply.first != 250 && reply.first != 251){            if (reply.first == 412)                throw std::runtime_error("rcpt TO error: RecipientsRefused");        }    }    /*     * rcpt TO:成功,DATA:开始     */    return Data(msg);}smtp::response smtp::SendMail (const string from_addr, const list<string> to_addrs_list, istream& input){   /*    * 可从文件或标准输出读,方便使用    */    string msg;    while(input){        string buf;        std::getline(input,buf);        msg.append (buf + "\n"); //getline返回的行里没有"\n"    }    return SendMail (from_addr,to_addrs_list,msg);}string smtp::Get_Line(){    /*     *服务器返回的行可能会有'\n'或'\r\n',页getline会把'\n'去掉.     * 因此只要检查是否有'\r',有侧去掉;     */    size_t n = read_until(_Sock, _Streambuf, '\n');    std::istream is(&_Streambuf);    std::string line;    std::getline(is, line);    /*     * getline会     */    if (boost::iends_with(line, CR))        line.pop_back ();    return line;}smtp::response smtp::Get_Reply(){    int code;    string msg;    while(true){       string line(Get_Line ());       stringstream sst(line);       try{           sst >> code;           msg.append (line.data () + 4);           if (line[3] == ' ')               break;       } catch (std::exception e){           throw std::runtime_error("Get_reply errror");       }   }   if (_DebugLevel)       logger().debug (str(format("*Get_Reply:*: %d %s") %code %msg));   return response ({code,msg});}void smtp::Put_Cmd(const string cmd, const string endline){    /*     * 发送命令,行结束符endline默认是'\r\n'     */    string line = cmd + endline;    size_t n = write(_Sock,buffer(line.data (),line.size ()));    assert(n == line.size ());    if (_DebugLevel)        logger().debug ("*Put_Cmd*: " + cmd);}smtp::response smtp::Do_Cmd(const string cmd){    Put_Cmd(cmd);    return Get_Reply();}smtp::response smtp::Data(const string msg){    auto reply = Do_Cmd ("DATA");    if (reply.first != 354)        throw std::runtime_error("DATA error");    /*     *  DATA成功,开始发送内容     */    stringstream sst(msg);    while(sst){        string line;        std::getline(sst,line);        if (boost::istarts_with(line, LF))            line.erase (line.begin ());        if (boost::iends_with(line, CR))            line.pop_back ();        Put_Cmd (line);    }    reply = Do_Cmd (".");    if (reply.first != 250)        if (reply.first != 421)            throw std::runtime_error("SendMail error");    /*     * 内容发达成功     */    return reply;}}

下一步:写一个邮件的生成器和解释器

0 0
原创粉丝点击