用socket(asio)实现了smtp的几个简单的指令

8 篇文章 0 订阅

测试主程序

#include <iostream>
#include<boost/asio.hpp>
#include"logging.h"
#include"smtplib.h"

using namespace std;
using namespace boost::asio;
using namespace logging;
using namespace smtplib;


int main()
{
    try{
        io_service i;
        smtp s(i);
        s.set_debuglevel (true);
        s.connect ("smtp.qq.com");  //服务器地址
        s.helo ("******@qq.com");   //HELO指令,本帐号
        s.login ("*****@qq.com","******"); //auth loginr指令,分另为用户名和密码
        s.sendmail ("from***@qq.com","to****@qq.com","Subject","body_english only","copy_t0***@qq.com"); 
        //本帐号地址---接收地址----主题-----邮件正文----抄送地址
        //编码问题比较复杂.目前只能发送英文邮件内容.
    }

    catch (std::exception e)
    {
        cout << e.what ();
    }
}


smtplib.h的头文件:

#ifndef SMTPLIB_H
#define SMTPLIB_H

#include<iostream>
#include<string>
#include<sstream>
#include<sstream>
#include<boost/asio.hpp>
#include<boost/format.hpp>
#include"logging.h" //昨天的日志类,
#include"internal/internal.h"  //只包含一个网上下载的base64算法

namespace smtplib {

using namespace std;
using namespace boost::asio;
using namespace logging;//昨天编写的logger类,昨天的版本实现和定义写在一个头文件里,
                        //类内定义了静态变量,当重复包含时,会报重定义的错,已收复这个bug
class smtp
{
public:
    smtp(io_service& i);  
    ~smtp(); 
    void set_debuglevel(bool level);  //设定调试级别,抄python的smtplib
    void connect (const string hostname, const string service = "smtp");
    void send_cmd(const string cmd);  
    void helo(std::string name);  
    string get_reply(int& retvcode);

    void login(const string username, const string password);
    void noop();
    void quit();
    void sendmail(const string from_addr,  //发送地址,本帐号
                  const string to_addr, // 接收地址
                  const string subject, //主题
                  const string body, //邮件正文,只能发英文
                  const string cc);//抄送

private:
    io_service& _io_service;
    ip::tcp::socket _socket;
    int debuglevel;

    const string body_decode(const string body);  //用于生成邮件正文的编码

};

}

#endif // SMTPLIB_H

smtplib.cpp实现:

#include"smtplib.h"


namespace smtplib{

using namespace std;
using namespace boost::asio;
using namespace internal;
smtp::smtp(io_service &i):_io_service(i),_socket(i){
    debuglevel = 0;
}

smtp::~smtp (){
    quit (); //实例析构时发送QUIT指令
}

void smtp::set_debuglevel (bool level){
    debuglevel = level; //设置调试级别
}

void smtp::connect (const string hostname,const string service){
    ip::tcp::resolver resolver(_io_service);
        ip::tcp::resolver::query query(hostname, service);
        ip::tcp::resolver::iterator iter;
        ip::tcp::resolver::iterator enditer;
        boost::system::error_code err;
        for(iter = resolver.resolve(query); iter != enditer; ++iter){
            _socket.connect (*iter,err); 
            if (!err)
                break;  //跌代测试服务器地址.连上了就break,否则close,继续迭代
            _socket.close ();
        }
        if(err){
            throw runtime_error(err.message ()); //找不到服务器,抛出异常
        }


        logger().info ("connected");   //连接成功,记录下

}

void smtp::send_cmd (const string cmd){ //抄python的SMTP.docmd(cmd, args='')
    boost::system::error_code err;
    _socket.write_some(buffer(cmd.data (),cmd.size ()),err);

    if (err)
        throw runtime_error(err.message ());  //写入出错.抛出异常

    int retvcode; //retvcode是答应码
    string reply = get_reply (retvcode);  //reply是答应的内容

    if(retvcode >= 400)  //答应码大于400表示出错?抛出一个SmtpError,继承run_timeerror. 
        throw SmtpError(reply.data ());

    if (debuglevel)
        logger().debug (reply);  //设置了调试级别就写一个日志
}


void smtp::helo (string name){
    string cmd = "HELO "+ name + "\r\n";  //HELO指令
    send_cmd (cmd);
}

string smtp::get_reply(int &retvcode){  //获得应内容,设置retvcode答应码,返回答应内容
    char buf[124];
    boost::system::error_code err;
    int n = _socket.read_some(buffer(buf,sizeof(buf)),err);
    if (err)
        throw runtime_error(err.message ());
    buf[n-1] = '\0';    //去掉换行符

    istringstream is(buf);
    is >> retvcode;  //提取答应码

    return buf;

}

void smtp::login (const string username, const string password){
    helo(username);

    send_cmd ("auth login\r\n");//auto login指令
    send_cmd (get_base64 (username)+ "\r\n");  //get_base64是在网上下载的算法,就不贴出来了
    send_cmd (get_base64 (password) + "\r\n");
}

void smtp::noop(){
    send_cmd ("noop\r\n");
}

void smtp::quit(){
    send_cmd ("quit\r\n");
}

void smtp::sendmail(const string from_addr,
                    const string to_addr,
                    const string subject,
                    const string body,
                    const string cc){  
    send_cmd ("mail FROM:" + from_addr + "\r\n");
    send_cmd ("rcpt TO:" + to_addr + "\r\n");
    send_cmd ("data\r\n");

    string data = str(format("From:%s\r\nTo:%s\r\nSubject:%s\r\nCc:%s\r\n%s\r\n.\r\n")
                      %from_addr
                      %to_addr
                      %subject
                      %cc
                      %body_decode (body));//body_decode设置邮正文的格式
    send_cmd (data);

}

//body_decode设置邮正文的格式,比较复杂.直接用硬编码给出
//格式是直接抄126邮件发过来的邮件
const string smtp::body_decode(const string body){
    string retval;
    retval.append ("Content-Type: text/plain; charset=GBK\r\n");
    retval.append ("Content-Transfer-Encoding: base64\r\n");
    retval.append ("\r\n");
    retval.append (get_base64 (body));

    return retval;
}

}

收到邮件:


还有日志输出

0.2015-03-29T20:42:57.252910 <info> : connected
1.2015-03-29T20:42:57.270519 <debug> : 220 smtp.qq.com Esmtp QQ Mail Server
2.2015-03-29T20:42:57.270519 <debug> : 250 smtp.qq.com
3.2015-03-29T20:42:57.289488 <debug> : 250 smtp.qq.com
4.2015-03-29T20:42:57.310737 <debug> : 334 *************
5.2015-03-29T20:42:57.341512 <debug> : 334 *************
6.2015-03-29T20:42:57.396468 <debug> : 235 Authentication successful
7.2015-03-29T20:42:57.418632 <debug> : 250 Ok
8.2015-03-29T20:42:57.442891 <debug> : 250 Ok
9.2015-03-29T20:42:57.462881 <debug> : 354 End data with <CR><LF>.<CR><LF>
10.2015-03-29T20:42:57.704964 <debug> : 250 Ok: queued as
11.2015-03-29T20:42:57.809904 <debug> : 221 Bye



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值