Windows下实现SMTP发送邮件

(1)建立TCP连接
(2)客户端发送HELO命令以标识发件人的身份,服务器以OK作为响应,表明准备接收

memset(buf, 0, 1500);
sprintf(buf, "EHLO HYL-PC\r\n");
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
cout << "EHLO REceive: " << rbuf << endl;

(3)使用AUTH命令登录SMTP服务器,输入用户名和密码(用户名和密码要用base64进行加密)

memset(buf, 0, 1500);
sprintf(buf, "AUTH LOGIN\r\n");
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
cout << "Auth Login Receive: " << rbuf << endl;

memset(buf, 0, 1500);
sprintf(buf, username);//user
memset(login, 0, 128);
EncodeBase64(login, buf, strlen(buf));
sprintf(buf, "%s\r\n", login);
send(sockfd, buf, strlen(buf), 0);
cout << "Base64 UserName: " << buf << endl;
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
cout << "User Login Receive: " << rbuf << endl;

sprintf(buf, password);//password
memset(pass, 0, 128);
EncodeBase64(pass, buf, strlen(buf));
sprintf(buf, "%s\r\n", pass);
send(sockfd, buf, strlen(buf), 0);
cout << "Base64 Password: " << buf << endl;
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
cout << "Send Password Receive: " << rbuf << endl;

(4)客户端发送MAIL命令输入发件人邮箱地址,服务器以OK作为响应

memset(buf, 0, 1500);
sprintf(buf, "MAIL FROM: <%s>\r\n", username);
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
cout << "set Mail From Receive: " << rbuf << endl;

(5)客户端发送RCPT命令,标识该电子邮件的计划接收人,服务器以OK作为响应

sprintf(buf, "RCPT TO:<%s>\r\n", email);
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
cout << "Tell Sendto Receive: " << rbuf << endl;

(6)协商结束后,使用DATA命令发送

sprintf(buf, "DATA\r\n");
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
cout << "Send Mail Prepare Receive: " << rbuf << endl;

(7)以"."号表示结束,输入内容一起发送出去

sprintf(buf, "%s\r\n.\r\n", body);
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
cout << "Send Mail Receive: " << rbuf << endl;

(8)结束此次发送,用QUIT命令退出

sprintf(buf, "QUIT\r\n");
send(sockfd, buf, strlen(buf), 0);
memset(rbuf, 0, 1500);
recv(sockfd, rbuf, 1500, 0);
cout << "Quit Receive: " << rbuf << endl;

完整Code:

#define _CRT_SECURE_NO_WARNINGS

#include<windows.h>
#include<stdio.h>
#include<WinSock.h>
#include<iostream>

#pragma comment(lib,"ws2_32")

using namespace std;

struct Base64Date6
{
    unsigned int d4 : 6;
    unsigned int d3 : 6;
    unsigned int d2 : 6;
    unsigned int d1 : 6;
};

//  协议中加密部分使用的是base64方法
char ConvertToBase64(char c6);
void EncodeBase64(char*dbuf, char*buf128, int len);
void SendMail(char*email, char*body, char* hostname, short port, char *username, char *password);
int  OpenSocket(struct sockaddr *addr);

int main(int argc, char *argv[])
{
    char *EmailTo = argv[1];
    char *host = argv[2];
    char *port = argv[3];
    char *user = argv[4];
    char *pass = argv[5];
    char *subject = argv[6];
    char *filename = argv[7];

    char *EmailContents = new char[20000];

    char *From = new char[128];
    sprintf(From, "From: <%s>\r\n", user);
    char *To = new char[128];
    sprintf(To, "To: <%s>\r\n", EmailTo);
    char *sub = new char[128];
    sprintf(sub, "Subject: %s\r\n\r", subject);

    short porttemp = 0;
    for (int i = 0; i < strlen(port); i++)
    {
        porttemp = porttemp * 10 + port[i] - '0';
    }
    FILE *fp;
    fp = fopen(filename, "rb");
    if (!fp)
    {
        printf("File path error\n");
        return false;
    }

    //打开传送内容的文件夹并读取到缓冲区
    fseek(fp, 0L, SEEK_END);
    int fileSize = ftell(fp);
    fseek(fp, 0L, SEEK_SET);
    cout << fileSize << endl;
    char *content = (char*)malloc(sizeof(char) * fileSize);
    fread(content, 1, fileSize, fp);
    cout << content << endl;
    fclose(fp);

    sprintf(EmailContents, "%s%s%s%s", From, To, sub, content);
    cout << EmailContents << endl;
    SendMail(EmailTo, EmailContents, host, porttemp, user, pass);
    system("PAUSE");
    return 0;
}

// 发送邮件
void SendMail(char*email, char*body, char* hostname, short port, char *username, char *password)
{
    int sockfd = { 0 };
    char buf[1500] = { 0 };
    char rbuf[1500] = { 0 };
    char login[128] = { 0 };
    char pass[128] = { 0 };
    WSADATA WSAData;
    struct sockaddr_in their_addr = { 0 };
    WSAStartup(MAKEWORD(2, 2), &WSAData);
    memset(&their_addr, 0, sizeof(their_addr));
    their_addr.sin_family = AF_INET;
    their_addr.sin_port = htons(port);
    hostent*hptr = gethostbyname(hostname);
    memcpy(&their_addr.sin_addr.S_un.S_addr, hptr->h_addr_list[0], hptr->h_length);

    printf("IP of %s is : %d:%d:%d:%d\n",
        hostname,
        their_addr.sin_addr.S_un.S_un_b.s_b1,
        their_addr.sin_addr.S_un.S_un_b.s_b2,
        their_addr.sin_addr.S_un.S_un_b.s_b3,
        their_addr.sin_addr.S_un.S_un_b.s_b4);

    // 连接邮箱服务器,如果连接后没有响应,则2 秒后重新连接
    sockfd = OpenSocket((struct sockaddr *)&their_addr);
    memset(rbuf, 0, 1500);
    while (recv(sockfd, rbuf, 1500, 0) == 0)
    {
        cout << "reconnect..." << endl;
        Sleep(2);
        sockfd = OpenSocket((struct sockaddr *)&their_addr);
        memset(rbuf, 0, 1500);
    }

    cout << rbuf << endl;
    
    // EHLO
    memset(buf, 0, 1500);
    sprintf(buf, "EHLO HYL-PC\r\n");
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    cout << "EHLO REceive: " << rbuf << endl;

    // AUTH LOGIN
    memset(buf, 0, 1500);
    sprintf(buf, "AUTH LOGIN\r\n");
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    cout << "Auth Login Receive: " << rbuf << endl;

    // USER
    memset(buf, 0, 1500);
    sprintf(buf, username);//user
    memset(login, 0, 128);
    EncodeBase64(login, buf, strlen(buf));
    sprintf(buf, "%s\r\n", login);
    send(sockfd, buf, strlen(buf), 0);
    cout << "Base64 UserName: " << buf << endl;
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    cout << "User Login Receive: " << rbuf << endl;

    // PASSWORD
    sprintf(buf, password);//password
    memset(pass, 0, 128);
    EncodeBase64(pass, buf, strlen(buf));
    sprintf(buf, "%s\r\n", pass);
    send(sockfd, buf, strlen(buf), 0);
    cout << "Base64 Password: " << buf << endl;
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    cout << "Send Password Receive: " << rbuf << endl;

    // MAIL FROM
    memset(buf, 0, 1500);
    sprintf(buf, "MAIL FROM: <%s>\r\n", username);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    cout << "set Mail From Receive: " << rbuf << endl;

    // RCPT TO 第一个收件人
    sprintf(buf, "RCPT TO:<%s>\r\n", email);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    cout << "Tell Sendto Receive: " << rbuf << endl;

    // DATA 准备开始发送邮件内容
    sprintf(buf, "DATA\r\n");
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    cout << "Send Mail Prepare Receive: " << rbuf << endl;

    // 发送邮件内容,\r\n.\r\n内容结束标记
    sprintf(buf, "%s\r\n.\r\n", body);
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    cout << "Send Mail Receive: " << rbuf << endl;

    // QUIT
    sprintf(buf, "QUIT\r\n");
    send(sockfd, buf, strlen(buf), 0);
    memset(rbuf, 0, 1500);
    recv(sockfd, rbuf, 1500, 0);
    cout << "Quit Receive: " << rbuf << endl;

    //清理工作
    closesocket(sockfd);
    WSACleanup();
    return;
}

//打开TCP Socket连接
int OpenSocket(struct sockaddr *addr)
{
    int sockfd = 0;
    sockfd = socket(PF_INET, SOCK_STREAM, 0);
    if (sockfd <0)
    {
        cout << "Open sockfd(TCP) error!" << endl;
        exit(-1);
    }
    if (connect(sockfd, addr, sizeof(struct sockaddr))<0)
    {
        cout << "Connect sockfd(TCP) error!" << endl;
        exit(-1);
    }
    return sockfd;
}

// base64的实现
void EncodeBase64(char *dbuf, char *buf128, int len)
{
    struct Base64Date6 *ddd = NULL;
    int i = 0;
    char buf[256] = { 0 };
    char *tmp = NULL;
    char cc = '\0';
    memset(buf, 0, 256);
    strcpy(buf, buf128);
    for (i = 1; i <= len / 3; i++)
    {
        tmp = buf + (i - 1) * 3;
        cc = tmp[2];
        tmp[2] = tmp[0];
        tmp[0] = cc;
        ddd = (struct Base64Date6*)tmp;
        dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1);
        dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2);
        dbuf[(i - 1) * 4 + 2] = ConvertToBase64((unsigned int)ddd->d3);
        dbuf[(i - 1) * 4 + 3] = ConvertToBase64((unsigned int)ddd->d4);
    }
    if (len % 3 == 1)
    {
        tmp = buf + (i - 1) * 3;
        cc = tmp[2];
        tmp[2] = tmp[0];
        tmp[0] = cc;
        ddd = (struct Base64Date6*)tmp;
        dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1);
        dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2);
        dbuf[(i - 1) * 4 + 2] = '=';
        dbuf[(i - 1) * 4 + 3] = '=';
    }
    if (len % 3 == 2)
    {
        tmp = buf + (i - 1) * 3;
        cc = tmp[2];
        tmp[2] = tmp[0];
        tmp[0] = cc;
        ddd = (struct Base64Date6*)tmp;
        dbuf[(i - 1) * 4 + 0] = ConvertToBase64((unsigned int)ddd->d1);
        dbuf[(i - 1) * 4 + 1] = ConvertToBase64((unsigned int)ddd->d2);
        dbuf[(i - 1) * 4 + 2] = ConvertToBase64((unsigned int)ddd->d3);
        dbuf[(i - 1) * 4 + 3] = '=';
    }
    return;
}

char ConvertToBase64(char uc)
{
    if (uc <26)
    {
        return 'A' + uc;
    }
    if (uc <52)
    {
        return 'a' + (uc - 26);
    }
    if (uc <62)
    {
        return '0' + (uc - 52);
    }
    if (uc == 62)
    {
        return '+';
    }
    return '/';
}
 用法:SMTP.exe xxx@qq.com smtp.163.com 25 xxx@163.com password subject test.txt

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 103,703评论 13 125
  • 一、概念(载录于:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436...
    yuantao123434阅读 5,843评论 5 149
  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 5,206评论 4 12
  • Http协议详解 标签(空格分隔): Linux 声明:本片文章非原创,内容来源于博客园作者MIN飞翔的HTTP协...
    Sivin阅读 3,887评论 3 82
  • 1240万:7日,“两会”工作扶贫办指出,去年全年减少1240万农村贫困人口,贫困地区农村居民人均可支配收入增速高...
    金蛛金服阅读 29评论 0 1