c++ 发邮件(含附件)

本程序在vs2013测试通过,一共3个文件,发邮件的程序封装为Csmtp 类。

这里写图片描述

1,测试用的主函数


//
#include "Csmtp.h"
#pragma comment(lib, "Kernel32.lib")  

int main()
{  

    Csmtp mail(
        25,
        "smtp.126.com",
        "[email protected]",// 来源邮箱
        "pwd",
        "[email protected]" //目标邮箱
        );

    if (!mail.CReateSocket())
    {
        cout << "ReateSocket failed!" << endl;
        return -1;//
    }
    mail.setTitle("test mail");
    mail.setContent("this is content.");

    mail.addfile("test1.png"); //添加附件
    mail.addfile("test2.png"); //添加附件

    mail.SendMail(); //类主函数

    return 0;  
} 

2, Csmtp类定义

#include <iostream>  
#include <string>  
#include <vector>
#include <fstream>  

#include <WinSock2.h>  //适用平台 Windows

#pragma  comment(lib, "ws2_32.lib") /*链接ws2_32.lib动态链接库*/ 
  // POP3服务器(端口:110) Csmtp服务器(端口:25) 
using namespace std;
class Csmtp  
{  

    int port;  
    string domain;  
    string user;  
    string pass;  
    string target;  
    string title;  //邮件标题
    string content;  //邮件内容


    HOSTENT* pHostent;
    SOCKET sockClient;  //客户端的套接字
    vector <string> filename;  //存储附件名的向量

public: 

    Csmtp(  
        int _port, //端口25
        string _domain,     //域名
        string _user,       //发送者的邮箱
        string _pass,       //密码
        string _target)     //目标邮箱
    :port(_port),domain(_domain),user(_user),pass(_pass),   target(_target){};//内容 
    bool CReateSocket();
    void setTitle(string tem){title = tem;}
    void setContent(string tem){content = tem;}

    int SendAttachment(SOCKET &sockClient);
    int SendMail();
    void addfile(string str){filename.push_back(str);}

};  

3, Csmtp 类的实现

#include "Csmtp.h"
//#include <afx.h>//异常类
static const char base64Char[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";  
char* base64Encode(char const* origSigned, unsigned origLength)  
{  
    unsigned char const* orig = (unsigned char const*)origSigned; // in case any input bytes have the MSB set  
    if (orig == NULL) return NULL;  

    unsigned const numOrig24BitValues = origLength / 3;  
    bool havePadding = origLength > numOrig24BitValues * 3;  
    bool havePadding2 = origLength == numOrig24BitValues * 3 + 2;  
    unsigned const numResultBytes = 4 * (numOrig24BitValues + havePadding);  
    char* result = new char[numResultBytes + 3]; // allow for trailing '/0'  

    // Map each full group of 3 input bytes into 4 output base-64 characters:  
    unsigned i;  
    for (i = 0; i < numOrig24BitValues; ++i)  
    {  
        result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F];  
        result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F];  
        result[4 * i + 2] = base64Char[((orig[3 * i + 1] << 2) | (orig[3 * i + 2] >> 6)) & 0x3F];  
        result[4 * i + 3] = base64Char[orig[3 * i + 2] & 0x3F];  
    }  

    // Now, take padding into account.  (Note: i == numOrig24BitValues)  
    if (havePadding)  
    {  
        result[4 * i + 0] = base64Char[(orig[3 * i] >> 2) & 0x3F];  
        if (havePadding2)  
        {  
            result[4 * i + 1] = base64Char[(((orig[3 * i] & 0x3) << 4) | (orig[3 * i + 1] >> 4)) & 0x3F];  
            result[4 * i + 2] = base64Char[(orig[3 * i + 1] << 2) & 0x3F];  
        }  
        else  
        {  
            result[4 * i + 1] = base64Char[((orig[3 * i] & 0x3) << 4) & 0x3F];  
            result[4 * i + 2] = '=';  
        }  
        result[4 * i + 3] = '=';  
    }  

    result[numResultBytes] = '\0';  
    return result;  
}  


int Csmtp::SendAttachment(SOCKET &sockClient) /*发送附件*/  
{  
    for (std::vector<string>::iterator iter = filename.begin();iter != filename.end(); iter++)  
    {  
        cout << "Attachment is sending··· " << endl; 

        string path=*iter;
        ifstream ifs(path, ios::in | ios::binary); //'或链接2个属性,以输入、二进制打开'
        if (false == ifs.is_open())  
        {  
            cout<<"无法打开文件!"<<endl;
            return 1; 
        }  

        string sendstring;  
        sendstring = "--@boundary@\r\nContent-Type: application/octet-stream; name=\"1.jpg\"\r\n";  
        sendstring += "Content-Disposition: attachment; filename=\"1.jpg\"\r\n";  
        sendstring += "Content-Transfer-Encoding: base64\r\n\r\n";  
        send(sockClient, sendstring.c_str(), sendstring.length(), 0); 

        //infile.read((char*)buffer,sizeof(数据类型));

        // get length of file:
        ifs.seekg (0, ifs.end);
        int length = ifs.tellg();
        ifs.seekg (0, ifs.beg);
        cout<<"length:"<<length<<endl;
        // allocate memory:
        char * buffer = new char [length];
        // read data as a block:
        ifs.read (buffer,length);
        ifs.close();
        char *pbase; 
        pbase = base64Encode(buffer, length);  
        delete[]buffer; 
        string str(pbase);
        delete[]pbase; 
        str+="\r\n";
        int err =send(sockClient, str.c_str(), strlen(str.c_str()), 0);  

        if (err != strlen(str.c_str()))  
        {  
            cout << "文件传送出错!" << endl;  
            return 1;  
        }  
    }
    return 0;
}  


bool Csmtp::CReateSocket()  
{ 
    WSADATA wsaData;  
    WORD wVersionRequested = MAKEWORD(2, 1);  
    //WSAStarup,即WSA(Windows SocKNDs Asynchronous,Windows套接字异步)的启动命令
    int err = WSAStartup(wVersionRequested, &wsaData); 
    cout<<"WSAStartup(0:successful):"<<err<<endl;

    char namebuf[128];    //获得本地计算机名
    string ip_list;
    if(0==gethostname(namebuf,128))  
    {  
        struct hostent* pHost;  //获得本地IP地址
        pHost=gethostbyname(namebuf);  //pHost返回的是指向主机的列表
        for (int i=0;pHost!=NULL&&pHost->h_addr_list[i]!=NULL;i++)  
        {
            string tem = inet_ntoa(*(struct in_addr *)pHost->h_addr_list[i]);
            ip_list += tem;
            ip_list += "\n";
        }  
    }  
    else  
    {  
        cout<<"获取主机信息失败..."<<endl ;  
    }
    //////////////////////////////////////////////////////////////////////////
    title=namebuf;// 邮件标题
    content=ip_list; //主机ip

    sockClient = socket(AF_INET, SOCK_STREAM, 0); //建立socket对象  

    pHostent = gethostbyname(domain.c_str()); //得到有关于域名的信息

    if (pHostent == NULL)
    {
        printf( "创建连接失败,也许没联网!\n" );
        return false;
    }

    return true;
}


int Csmtp::SendMail()
{
    char *ecode;

    char buff[500];  //recv函数返回的结果
    int err = 0; 
    string message; //

    SOCKADDR_IN addrServer;  //服务端地址
    addrServer.sin_addr.S_un.S_addr = *((DWORD *)pHostent->h_addr_list[0]); //得到smtp服务器的网络字节序的ip地址     



    addrServer.sin_family = AF_INET;  
    addrServer.sin_port = htons(port); //连接端口25 
    //int connect (SOCKET s , const struct sockaddr FAR *name , int namelen );
    err = connect(sockClient, (SOCKADDR*)&addrServer, sizeof(SOCKADDR));   //向服务器发送请求  
    cout<<"connect:"<<err<<endl;
    //telnet smtp.126.com 25 连接服务器结束
    buff[recv(sockClient, buff, 500, 0)]='\0';
    //cout<<"connect:"<<buff<<endl;

    message="ehlo 126.com\r\n";
    send(sockClient, message.c_str(), message.length(), 0); 

    buff[recv(sockClient, buff, 500, 0)]='\0';
    //cout<<"helo:"<<buff<<endl;

    message="auth login \r\n";
    send(sockClient, message.c_str(), message.length(), 0); 
    buff[recv(sockClient, buff, 500, 0)]='\0';
    //cout<<"auth login:"<<buff<<endl;
    //上传邮箱名
    message=user;  
    ecode = base64Encode(message.c_str(), strlen(message.c_str()));  
    message = ecode;  
    message += "\r\n";  
    delete[]ecode;  
    send(sockClient, message.c_str(), message.length(), 0); 
    buff[recv(sockClient, buff, 500, 0)]='\0';
    //cout<<"usrname:"<<buff<<endl;
    //上传邮箱密码
    message=pass;  
    ecode = base64Encode(message.c_str(), strlen(message.c_str()));  
    message = ecode;  
    delete[]ecode;  
    message += "\r\n";  
    send(sockClient, message.c_str(), message.length(), 0); 
    buff[recv(sockClient, buff, 500, 0)]='\0';
    //cout<<"password:"<<buff<<endl;

    message="mail from:<"+user+">\r\nrcpt to:<"+target+">\r\n";
    send(sockClient, message.c_str(), message.length(), 0); 
    buff[recv(sockClient, buff, 500, 0)]='\0';
    //cout<<"mail from: "<<buff<<endl;
    buff[recv(sockClient, buff, 500, 0)]='\0';
    //cout<<"rcpt to: "<<buff<<endl;

    message="data\r\n";//data要单独发送一次
    send(sockClient, message.c_str(), message.length(), 0); 
    buff[recv(sockClient, buff, 500, 0)]='\0';
    //cout<<"data: "<<buff<<endl;
    ///-----------------------------------------DATA-------------------------------------
    //要使用Csmtp 发送附件, 需要对Csmtp 头信息进行说明, 改变Content-type 及为每一段正文添加BOUNDARY 名,
    cout<<"-------------------DATA------------------------"<<endl;
    //  头
    message="from:"+user+"\r\nto:"+target+"\r\nsubject:"+title+"\r\n";
    message += "MIME-Version: 1.0\r\n";  
    message += "Content-Type: multipart/mixed;boundary=@boundary@\r\n\r\n";  
    send(sockClient, message.c_str(), message.length(), 0); 

    //  正文
    message = "--@boundary@\r\nContent-Type: text/plain;charset=\"gb2312\"\r\n\r\n"+content+"\r\n\r\n";   
    send(sockClient, message.c_str(), message.length(), 0); 

    //------------------------------------------------------------------------------------------------
    //  发送附件

    SendAttachment(sockClient);

    /*发送结尾信息*/ 
     message = "--@boundary@--\r\n.\r\n";  
    send(sockClient, message.c_str(), message.length(), 0); 
    buff[recv(sockClient, buff, 500, 0)]='\0';
    //cout<<"end_qwertyuiop:"<<buff<<endl;

    message="QUIT\r\n"; 
    send(sockClient, message.c_str(), message.length(), 0); 
    buff[recv(sockClient, buff, 500, 0)]='\0';
    cout<<"Send mail is finish:"<<buff<<endl;
    return 0;
}

容易理解的简化版可以点击->这里

猜你喜欢

转载自blog.csdn.net/sinat_36219858/article/details/80439782
今日推荐