用CBrother脚本实现smtp协议发送一份邮件

用CBrother脚本实现smtp协议发送一份邮件

之前用CBrother脚本写了一个拯救“小霸王服务器”的程序,公司人用着都挺好用,但是有时候谁重启了服务器其他人不知道,造成了多人多次重启,每个人都抢救一遍,大家一再要求我添加功能,有一个人重启后给其他人发一封邮件。

靠,真是“饱暖思淫欲”,之前没有这个重启系统的时候,都得连到服务器上去重启,哎。。。人啊。。。。。

有“”祖传背锅侠“称号的我也只能硬着头皮去做了,于是用CBrother实现了smtp协议,可以发送邮件了

先来看看封装的发邮件EMailSender类的用法:

//EMailSender是我封装的邮件发送类,全局new一个
var mailSender = new EMailSender();
function main()
{
    //启动邮件发送
    mailSender.start();

    //创建一个封邮件 Mail是我封装的一个描述邮件内容的类
    var mail = new Mail();
    //设置发送者的邮箱 的 名称 地址 密码
    mail.setSender("zhangZsan","zhangZsan1122334@163.com","123456789");
    //设置收件人 多个收件人就添加多条  SEND_TO表示是接收人
    mail.addRecipient("boss","myboss_aaaa123@qq.com",SEND_TO);
    mail.addRecipient("erhuo","erhuo_aaaa123@qq.com",SEND_TO);
    //设置抄送邮箱 SEND_CC表示抄送
    mail.addRecipient("nvshen","nvshen_aaa123@163.com",SEND_CC);
    //设置秘密抄送 SEND_BCC表示秘密抄送
    mail.addRecipient("erdaye","erdaye_aaa123@qq.com",SEND_BCC);
    //设置右键标题
    mail.setTitle("服务器被重启了");
    //设置右键内容
    mail.setValue("服务器被erhuo重启了.");
    //发送邮件
    mailSender.sendMail(mail);

    //sendMail调用一次发一封,调用两次发两封

    while (1)
    {
        Sleep(1000);
    }
}

使用还是很简单了,对于封装,我是认真的,哈哈。当然,这里面的邮箱地址都是胡写的,你不用去163试密码了。。。。。

再来看看实现代码:

//包含cbrother的socket模块
import CBSocket.code

//这些定义是发送邮件的步骤,可以忽略不看
const MAIL_STEP_NORMAL = 0;
const MIAL_STEP_EHLO = 1;
const MAIL_STEP_LOGIN = 2;
const MAIL_STEP_ACCOUNT = 3;
const MAIL_STEP_PWD = 4;
const MAIL_STEP_FROM = 5;
const MAIL_STEP_DATA = 6;
const MAIL_STEP_QUIT = 7;
const MAIL_STEP_OVER = 8;

//邮件内容分割线,邮件格式协议里要的,你可以改成自己的
const SPLIC_MAIL = "--_CBROTHER_MAIL_202020202020";

//收件人类型
const SEND_TO = 0;    //接收者
const SEND_CC = 1;    //抄送
const SEND_BCC = 2;    //秘密抄送

//邮件接收者类
class MailUser
{
    var Name;    //名字
    var Addr;    //邮箱地址
    var Type;    //类型
}

//描述一封右键
class Mail
{
    var _SmtpHost;    //smpt服务器地址
    var _Sender = new MailUser();      //发送者
    var _SendPwd;                      //发送者密码
    var _Recipient = new Array();      //接收者列表
    var _MailTitle;                    //邮件标题
    var _MailValue;                    //邮件内容

    //设置发送者信息
    function setSender(senderName,senderAddr,senderPwd)
    {
        var strArr = strsplit(senderAddr,"@");
        if (strArr.size() != 2)
        {
            return false;
        }
        
        this._SmtpHost = "smtp." + strArr[1];
        this._SendPwd = senderPwd;

        _Sender.Name = senderName;
        _Sender.Addr = senderAddr;
        return true;
    }

    //添加接收者
    function addRecipient(name,addr,type)
    {
        foreach (k,v : _Recipient)
        {
            if (v.Addr == addr)
            {
                v.Name = name;
                v.Type = type;
                return;                
            }  
        }

        var r = new MailUser();
        r.Addr = addr;
        r.Name = name;
        r.Type = type;
        _Recipient.add(r);
    }

    //设置右键标题
    function setTitle(title)
    {
        this._MailTitle = title;        
    }

    //设置右键内容
    function setValue(value)
    {
        this._MailValue = value;        
    }
}

//右键发送过程中需要的一些数据
class MailBuf
{
    var _mail;        //邮件 Mail类对象
    var _byteArray = new ByteArray();    //数据缓存
    var _step = MAIL_STEP_NORMAL;        //右键发送的步骤
    var _socketid;                        //这封优先的socketid
    var _recvsendidx = 0;                //发送接收者过程中的一个临时变量
}

//这个类是邮件发送的smtp协议的主要实现
class EMailSender
{
    var _tcpModule = new TcpModule();    //tcp模块
    var _Lock = new Lock();              //多线程互斥锁
    var _mailMap = new Map();            //存储邮件的map

    //启动邮件服务
    function start()
    {
        _tcpModule.setTcpAction(this);
        _tcpModule.start();
    }

    //发送一封邮件
    function sendMail(mail)
    {
        //连接对方smtp服务器
        var socketid = _tcpModule.connect(mail._SmtpHost,25);
        print "connect " + mail._SmtpHost + " "  +socketid;
        if (socketid == 0)
        {
            print "socketid == 0";
            return;            
        }
        
        //连接成功后将socketid和mail绑定,这里多线程有可能OnConnect回调先执行
        _Lock.lock();
        var mailbuf = _mailMap.get(socketid);
        if (mailbuf == null)
        {
            mailbuf = new MailBuf();
            mailbuf._socketid = socketid;
            _mailMap.add(socketid,mailbuf);
        }
        _Lock.unlock();

        mailbuf._mail = mail;
    }

    //连接上服务器
    function OnConnect(sock)
    {
        print "onconnect " + sock;
        _Lock.lock();
        var mailbuf = _mailMap.get(sock);
        if (mailbuf == null)
        {
            mailbuf = new MailBuf();
            mailbuf._socketid = socketid;
            _mailMap.add(socketid,mailbuf);
        }
        _Lock.unlock();

        if (mailbuf == null)
        {
            print "OnConnect mail is null";
            _tcpModule.closeSocket(sock);
            return;
        }
    }

    //和服务器连接断开
    function OnClose(sock)
    {
        print "onclose " + sock;
        _Lock.lock();
        _mailMap.remove(sock);
        _Lock.unlock();
    }

    //收到数据
    function OnRecv(sock,byteArray,len)
    {
        _Lock.lock();
        var mailbuf = _mailMap.get(sock);
        _Lock.unlock();

        if (mailbuf == null)
        {
            print "recv mail is null";
            _tcpModule.closeSocket(sock);
            return true;
        }

        mailbuf._byteArray.writeBytes(byteArray,len);        
        print "r:" + mailbuf._byteArray.getReadPos();
        print "w:" + mailbuf._byteArray.getWritePos();
        MakeMail(mailbuf);
        return true;
    }

    //从数据里获取一行,\r\n结束
    function GetLine(byteArray)
    {
        var rpos = byteArray.getReadPos();
        var wpos = byteArray.getWritePos();

        //print "rpos:" + rpos + " wpos:" + wpos;

        var res;
        for (var i = rpos; i < wpos ; i++)
        {
            if (byteArray.getByte(i) == '\r')
            {
                if (i + 1 < wpos)
                {
                    if (byteArray.getByte(i) == '\n')
                    {
                        res = byteArray.readString(i - rpos);
                        byteArray.copy(byteArray,0,i + 2,wpos - i - 2);
                        byteArray.setReadPos(0);
                        byteArray.setWritePos(wpos - i - 2);
                        break;
                    }
                }
                else
                {
                    return null;
                }
            }
            else if (byteArray.getByte(i) == '\n')
            {
                res = byteArray.readString(i - rpos);
                byteArray.copy(byteArray,0,i + 1,wpos - i - 1);
                byteArray.setReadPos(0);
                byteArray.setWritePos(wpos - i - 1);
                break;
            }
        }

        //print "end rpos:" + byteArray.getReadPos() + " wpos:" + byteArray.getWritePos();
        return res;
    }

    //验证服务器返回数据是否正确
    function RecvValue(mailbuf,str)
    {
        var value = GetLine(mailbuf._byteArray);
        if (value == null)
        {
            return 0;            
        }

        print value;
        //print strlen(value);

        var len = strlen(str);
        var lenvalue = strlen(value);
        if (lenvalue < len)
        {
            return 2;            
        }

        var getstr = strget(value,0,len);
        if (str != getstr)
        {
            return 2;            
        }
        return 1;
    }    
    
    //EHLO有特殊性,单数写一个函数
    function RecvEHLO(mailbuf,str)
    {
        while (true)
        {
            var value = GetLine(mailbuf._byteArray);
            if (value == null)
            {
                return 0;            
            }

            print value;
            //print strlen(value);

            var len = strlen(str);
            var lenvalue = strlen(value);
            if (lenvalue < len)
            {
                return 2;            
            }

            var getstr = strget(value,0,len);
            if (str != getstr)
            {
                return 2;            
            }

            if (strget(value,3,4) == " ")
            {
                return 1;                             
            }          
        }

        return 0;
    }

    //这里面主要就是smtp协议部分了,要看懂需要去学习一下
    function MakeMail(mailbuf)
    {
        switch (mailbuf._step)
        {
            case MAIL_STEP_NORMAL:
            {
                var res = RecvValue(mailbuf,"220");
                if(res == 2)
                {
                    print "MAIL_STEP_NORMAL mail send err!" + mailbuf._mail._SmtpHost;
                    break;
                }

                if (res == 1)
                {
                    var mailsend = "EHLO " +   mailbuf._mail._SmtpHost + "\r\n";
                    print mailsend;
                    this._tcpModule.sendData(mailbuf._socketid,mailsend);
                    mailbuf._step = MIAL_STEP_EHLO;
                }

                break;
            }
            case MIAL_STEP_EHLO:
            {
                var res = RecvEHLO(mailbuf,"250");
                if(res == 2)
                {
                    print "MIAL_STEP_EHLO mail send err!" + mailbuf._mail._SmtpHost;
                    break;
                }

                if (res == 1)
                {
                    var mailsend = "AUTH LOGIN\r\n";
                    print mailsend;
                    this._tcpModule.sendData(mailbuf._socketid,mailsend);
                    mailbuf._step = MAIL_STEP_LOGIN;
                }
                break;
            }
            case MAIL_STEP_LOGIN:
            {
                var res = RecvValue(mailbuf,"334");
                if(res == 2)
                {
                    print "MAIL_STEP_LOGIN mail send err!" + mailbuf._mail._SmtpHost;
                    break;
                }

                if (res == 1)
                {
                    var mailsend = base64_encode(mailbuf._mail._Sender.Addr) + "\r\n";
                    print mailsend;
                    this._tcpModule.sendData(mailbuf._socketid,mailsend);
                    mailbuf._step = MAIL_STEP_ACCOUNT;    
                }
                break;
            }
            case MAIL_STEP_ACCOUNT:
            {
                var res = RecvValue(mailbuf,"334");
                if(res == 2)
                {
                    print "MAIL_STEP_ACCOUNT mail send err!" + mailbuf._mail._SmtpHost;
                    break;
                }

                if (res == 1)
                {
                    var mailsend = base64_encode(mailbuf._mail._SendPwd) + "\r\n";
                    print mailsend;
                    this._tcpModule.sendData(mailbuf._socketid,mailsend);
                    mailbuf._step = MAIL_STEP_PWD;    
                }
                break;
            }
            case MAIL_STEP_PWD:
            {
                var res = RecvValue(mailbuf,"235");
                if(res == 2)
                {
                    print "MAIL_STEP_PWD mail send err!" + mailbuf._mail._SmtpHost;
                    break;
                }

                if (res == 1)
                {
                    var mailsend = "MAIL FROM: <" + mailbuf._mail._Sender.Addr + ">\r\n";
                    print mailsend;
                    this._tcpModule.sendData(mailbuf._socketid,mailsend);
                    mailbuf._step = MAIL_STEP_FROM;    
                }                   
                break;
            }
            case MAIL_STEP_FROM:
            {
                var res = RecvValue(mailbuf,"250");
                if(res == 2)
                {
                    print "MAIL_STEP_FROM mail send err!" + mailbuf._mail._SmtpHost;
                    break;
                }

                if (res == 1)
                {
                    if (mailbuf._recvsendidx < mailbuf._mail._Recipient.size())
                    {
                        var mailsend = "RCPT TO: <" + mailbuf._mail._Recipient[mailbuf._recvsendidx++].Addr + ">\r\n";
                        print mailsend;
                        this._tcpModule.sendData(mailbuf._socketid,mailsend);
                        mailbuf._step = MAIL_STEP_FROM;
                    }
                    else
                    {
                        var mailsend = "DATA\r\n";
                        print mailsend;
                        this._tcpModule.sendData(mailbuf._socketid,mailsend);
                        mailbuf._step = MAIL_STEP_DATA;
                    }
                }
                break;
            }
            case MAIL_STEP_DATA:
            {
                var res = RecvValue(mailbuf,"354");
                if(res == 2)
                {
                    print "MAIL_STEP_DATA mail send err!" + mailbuf._mail._SmtpHost;
                    break;
                }

                if (res == 1)
                {
                    var mailsend = MakeMailHead(mailbuf);
                    print mailsend;
                    this._tcpModule.sendData(mailbuf._socketid,mailsend);

                    mailsend = MakeMailValue(mailbuf);
                    print mailsend;
                    this._tcpModule.sendData(mailbuf._socketid,mailsend);
                    mailbuf._step = MAIL_STEP_QUIT;
                }
                break;
            }
            case MAIL_STEP_QUIT:
            {
                var res = RecvValue(mailbuf,"250");
                if(res == 2)
                {
                    print "MAIL_STEP_QUIT mail send err!" + mailbuf._mail._SmtpHost;
                    break;
                }

                if (res == 1)
                {
                    var mailsend = "QUIT\r\n";
                    this._tcpModule.sendData(mailbuf._socketid,mailsend);
                    mailbuf._step = MAIL_STEP_OVER;
                }

                break;
            }
            case MAIL_STEP_OVER:
            {
                var res = RecvValue(mailbuf,"221");
                if(res == 2)
                {
                    print "MAIL_STEP_OVER mail send err!" + mailbuf._mail._SmtpHost;
                    break;
                }              

                if (res == 1)
                {
                    this._tcpModule.closeSocket(mailbuf._socketid);
                    print "mail send success:" + mailbuf._mail._SmtpHost;
                }  
                break;
            }
            default:
            {
                break;
            }
        }
    }

    function MimeCode(basestr)
    {
        return "=?utf-8?b?" + base64_encode(basestr) + "?=";
    }

    function MakeMailHead(mailbuf)
    {
        var myTime = new Time(time() - 28800);
        var head = "Date: " + myTime.strftime("%a, %d %b %Y %H:%M:%S GMT") + "\r\n";
        
        head += "From: \"" + MimeCode(mailbuf._mail._Sender.Name) + "\" <" + mailbuf._mail._Sender.Addr + ">\r\n";
        head += "To: ";

        var ccmsg = "Cc: ";
        var ccflag = 0;
        var bccmsg = "Bcc: ";
        var bccflag = 0;
        for (var i = 0; i < mailbuf._mail._Recipient.size() ; i++)
        {
            var sender = mailbuf._mail._Recipient[i];
            if (sender.Type == SEND_TO)
            {
                if (i != 0)
                {
                    head += ",";
                }

                head += "\"" + MimeCode(sender.Name) + "\" <" + sender.Addr + ">";
            }
            else if (sender.Type == SEND_CC)
            {
                if (ccflag++ != 0)
                {
                    ccmsg += ",";
                }

                ccmsg += "\"" + MimeCode(sender.Name) + "\" <" + sender.Addr + ">";
            }
            else
            {
                if (bccflag++ != 0)
                {
                    bccmsg += ",";
                }

                bccmsg += "\"" + MimeCode(sender.Name) + "\" <" + sender.Addr + ">";
            }
        }

        head += "\r\n";

        if (ccmsg != "Cc: ")
        {
            head += ccmsg + "\r\n";            
        }

        if (bccmsg != "Bcc: ")
        {
            head += bccmsg + "\r\n";            
        }

        head += "Subject: " + MimeCode(mailbuf._mail._MailTitle) + "\r\n";

        head += "MIME-Version: 1.0\r\n";
        head += "Content-type: multipart/mixed; boundary=\"" + SPLIC_MAIL + "\"\r\n";
        head += "\r\n";

        return head;
    }

    function MakeMailValue(mailbuf)
    {
        var valuemsg = "--" + SPLIC_MAIL + "\r\n";
        valuemsg += "Content-Type: text/html; charset=utf-8\r\n";
        valuemsg += "Content-Transfer-Encoding: base64\r\n\r\n";
        valuemsg += base64_encode(mailbuf._mail._MailValue) + "\r\n";
        valuemsg += "\r\n--" + SPLIC_MAIL + "--\r\n" + ".\r\n";
        return valuemsg;
    }
}

我自认为封装的还是比较简单的,当然如果你要用这个代码发邮件,那么你自己的邮箱必须开启smtp授权,如何开启,不同厂商提供的邮箱方式都不一样,一般都是登录到邮箱里设置一个东西具体你可以百度一下自己的邮箱,比如搜索:163邮箱如何开启smtp,qq邮箱如何开启smtp等。

当运行了以后,接收方就收到了

 

 

 

 如果给手机上装上邮箱APP,允许后台推送,手机也会收到提醒,这可能是成本最低的实时通知到手机上的方式了吧。

posted @ 2020-07-16 08:58  无剑胜有剑  阅读(364)  评论(0编辑  收藏  举报