使用Tcp发送smtp邮件(以Qt为例)

3 篇文章 1 订阅
1 篇文章 0 订阅
使用Tcp发送smtp邮件(以Qt为例)

前言

  有时候我们想在自己的应用里添加发邮件的功能,但是很多比较底层的编程语言是不自带直接发邮件的函数的,所以使用这类编程语言要发邮件就要自己实现发邮件的功能。下面以Qt为例写一个发送邮件的demo。如果是急着用发送邮件的功能就直接翻到最下面的封装成ZSmtp类复制代码吧,如果想搞清楚原理,就接着往下看。

分析

准备工作

  打开Qt,创建一个项目,我这把项目名命名为:smtp_test
  在smtp_test.pro里添加一个库:

QT       += network

  添加这个库是为了可以使用Qt网络编程库,添加完后Ctrl+S保存。

用Tcp连接到smtp服务器

  万事开头难,要发邮件第一步当然是要连接到邮件的服务器。首先要选一个服务器,下面以qq邮箱为例。
  qq邮箱的smtp服务器地址是:smtp.qq.com,端口是:25
  那么用Qt应该怎么连接呢?是不是要自己实现一个连接服务器的类?不需要Qt里自带了一个封装好了的TcpSocket类,可以用它来直接连接qq邮箱的服务器。

代码详细解释

  打开mainwindow.h,在里面添加一个头文件:

#include <QTcpSocket>

  然后添加一个私有成员变量:

QTcpSocket *tcpSocket;		//用于连接服务器以及和服务器交互

  再添加三个公有槽:

public slots:
    void connectToServer();			//连接到服务器
    void disconnectFromServer();	//与服务器断开连接
    void getMessage();				//得到消息

  接下来,在mainwindow.ui里添加三个按键,分别命名为:connectButton disconnectButtonsendButton,分别用于连接、断开连接和发送消息。然后添加一个 QEditText命名为:messageEdit并设置为只读,然后添加一个QPlainTextEdit命名为:sendEdit。添加好以后把那三个按钮都转到槽,都选择clicked槽。
  然后在mainwindow.cpp的构造函数里添加:

tcpSocket = new QTcpSocket;	//实例化一个QTcpSocket对象,用于连接和交互

//连接到服务器调用connectToServer槽
connect(tcpSocket, SIGNAL(connected()), this, SLOT(connectToServer()));	

//断开连接调用disconnectToServer槽
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnectFromServer()));

//收到消息调用getMessage槽
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(getMessage()));

  并在mainwindow.cpp里把所有槽都实现了:

void MainWindow::connectToServer()	//连接到服务器
{
	//<font style=啥啥啥的 都是用于设置字体
	//我是想让不同事件添加到messageEdit的文本颜色不一样才搞得这么花里胡哨的
	//下面的所有槽的这种操作都是为了让程序显示得比较好看
    QString info = QString("<font style='color:green'>%1<br></font>")
    						.arg("连接到服务器");
    ui->messageEdit->append(info);	//连接到服务器时在messageEdit显示出来
}

void MainWindow::disconnectFromServer()	//断开连接
{
    QString info = QString("<font style='color:red'>%1<br></font>")
    						.arg("与服务器断开连接");
    ui->messageEdit->append(info);	//断开连接时在messageEdit显示出来
}

void MainWindow::getMessage()	//得到消息
{
	//获取得到的消息
    QByteArray message = tcpSocket->readAll();

	//防止中文乱码
    QString plainText = QString::fromLocal8Bit(message);

	//如果QTextEdit用到了富文本,就要用&lt;来替换<,用&gt;来替换>,复制无法显示
    plainText.replace("<", "&lt;").replace(">", "&gt;");
    QString info = \
    QString("<font style='color:black'>服务器:<br>%1</font>")
    			.arg(plainText);
    			
    //显示到messageEdit,如果QTextEdit用到了富文本,就只能用<br>来换行了
    ui->messageEdit
    ->append(info.replace("\r", "").replace("\n", "<br>"));
}

void MainWindow::on_connectButton_clicked()	//主动连接服务器
{
    tcpSocket->abort();

	//qq邮箱的服务器地址是smtp.qq.com,端口是25,连接到qq邮箱服务器
    tcpSocket->connectToHost("smtp.qq.com", 25);
}

void MainWindow::on_disconnectButton_clicked()	//主动断开连接
{
    tcpSocket->disconnectFromHost();
}

void MainWindow::on_sendButton_clicked()	//发送消息给服务器
{
	//获取要发送的文本
    QString plainText = ui->sendEdit->toPlainText();
    plainText.replace("\n", "\r\n").append("\r\n");
    QByteArray message = QByteArray().append(plainText);
    tcpSocket->write(message);
    plainText.replace("<", "&lt;").replace(">", "&gt;")
    QString info = QString("<font style='color:blue'>我:<br>%1</font>")
    					.arg(plainText);

	//如果QTextEdit用到了富文本,就只能用<br>来换行了
    ui->messageEdit->append(info.replace("\r", "").replace("\n", "<br>"));
    ui->sendEdit->clear();
}

如果你只想复制粘贴请直接看这里

  按照上述步骤完成后,mainwindow.h应该是这个样子:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpSocket>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QTcpSocket *tcpSocket;

public slots:
    void connectToServer();
    void disconnectFromServer();
    void getMessage();

private slots:
    void on_connectButton_clicked();
    void on_disconnectButton_clicked();
    void on_sendButton_clicked();

};

#endif // MAINWINDOW_H


  mainwindow.cpp应该是这个样子:

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    tcpSocket = new QTcpSocket;
    connect(tcpSocket, SIGNAL(connected()), this, SLOT(connectToServer()));
    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnectFromServer()));
    connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(getMessage()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::connectToServer()
{
    QString info = QString("<font style='color:green'>%1<br></font>").arg("连接到服务器");
    ui->messageEdit->append(info);
}

void MainWindow::disconnectFromServer()
{
    QString info = QString("<font style='color:red'>%1<br></font>").arg("与服务器断开连接");
    ui->messageEdit->append(info);
}

void MainWindow::getMessage()
{
    QByteArray message = tcpSocket->readAll();
    QString plainText = QString::fromLocal8Bit(message);
    plainText.replace("<", "&lt;").replace(">", "&gt;");
    QString info = QString("<font style='color:black'>服务器:<br>%1</font>").arg(plainText);
    ui->messageEdit->append(info.replace("\r", "").replace("\n", "<br>"));
}

void MainWindow::on_connectButton_clicked()
{
    tcpSocket->abort();
    tcpSocket->connectToHost("smtp.qq.com", 25);
}

void MainWindow::on_disconnectButton_clicked()
{
    tcpSocket->disconnectFromHost();
}

void MainWindow::on_sendButton_clicked()
{
    QString plainText = ui->sendEdit->toPlainText();
    plainText.replace("\n", "\r\n").append("\r\n");
    QByteArray message = QByteArray().append(plainText);
    tcpSocket->write(message);
    plainText.replace("<", "&lt;").replace(">", "&gt;");
    QString info = QString("<font style='color:blue'>我:<br>%1</font>").arg(plainText);
    ui->messageEdit->append(info.replace("\r", "").replace("\n", "<br>"));
    ui->sendEdit->clear();
}


  什么?你连mainwindow.ui都懒得自己弄?直接上文本的吧:

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
 <class>MainWindow</class>
 <widget class="QMainWindow" name="MainWindow">
  <property name="geometry">
   <rect>
    <x>0</x>
    <y>0</y>
    <width>725</width>
    <height>699</height>
   </rect>
  </property>
  <property name="windowTitle">
   <string>连接smtp服务器测试工具</string>
  </property>
  <widget class="QWidget" name="centralWidget">
   <layout class="QGridLayout" name="gridLayout">
    <item row="0" column="0" colspan="4">
     <widget class="QTextEdit" name="messageEdit">
      <property name="readOnly">
       <bool>true</bool>
      </property>
     </widget>
    </item>
    <item row="1" column="0" colspan="4">
     <widget class="QPlainTextEdit" name="sendEdit">
      <property name="maximumSize">
       <size>
        <width>16777215</width>
        <height>150</height>
       </size>
      </property>
     </widget>
    </item>
    <item row="2" column="0">
     <spacer name="horizontalSpacer">
      <property name="orientation">
       <enum>Qt::Horizontal</enum>
      </property>
      <property name="sizeHint" stdset="0">
       <size>
        <width>400</width>
        <height>20</height>
       </size>
      </property>
     </spacer>
    </item>
    <item row="2" column="1">
     <widget class="QPushButton" name="connectButton">
      <property name="text">
       <string>connect</string>
      </property>
     </widget>
    </item>
    <item row="2" column="2">
     <widget class="QPushButton" name="disconnectButton">
      <property name="text">
       <string>disconnect</string>
      </property>
     </widget>
    </item>
    <item row="2" column="3">
     <widget class="QPushButton" name="sendButton">
      <property name="text">
       <string>send</string>
      </property>
     </widget>
    </item>
   </layout>
  </widget>
  <widget class="QMenuBar" name="menuBar">
   <property name="geometry">
    <rect>
     <x>0</x>
     <y>0</y>
     <width>725</width>
     <height>26</height>
    </rect>
   </property>
  </widget>
  <widget class="QStatusBar" name="statusBar"/>
 </widget>
 <layoutdefault spacing="6" margin="11"/>
 <resources/>
 <connections/>
</ui>


  smtp_test.pro就加一行代码都不想自己写?

QT       += core gui
QT       += network

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = smtp_test
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

  要main.cpp的我怀疑你没用过Qt。

发送邮件测试

  之前的都是前戏,连接上smtp服务器只是开始,现在要用刚刚写好的那个程序来发邮件了。
  先看一个例子:

点connect
点connect

打招呼
打招呼1
打招呼2

250是成功的状态码。

提出要登陆认证
提出要登陆1
提出要登陆2

输入邮箱号(要转换为base64)
输入邮箱号1
输入邮箱号2

输入邮箱密码(也要转换为base64,密码这种东西我就不公开了)
输入密码1
输入密码2

235是认证通过的状态码。
235 Authentication successful
表示认证通过了。
认证能通过还有一个要求,就是用于发送邮件的邮箱一定要开启smtp服务,smtp服务不开启是不可能通过认证的。

填写发件人
填写发件人1

格式为:
MAIL FROM: <发件人邮箱号>

填写发件人2

250是成功的状态码。
在这里
250 Ok
表示这个发件人邮箱号是存在的。

填写收件人
填写收件人1

格式为:
RCPT TO: <收件人邮箱号>
我是为了测试方便才把发件人和收件人写成同一个的,可以不同。

填写收件人2

250是成功的状态码。
在这里
250 Ok
表示这个收件人邮箱号是存在的。

正文开始标志
正文开始1

发送DATA后就可以输入要发送的内容了。

正文开始2

它返回的文本:
End data with <CR><LF>.<CR><LF>
的意思是用\r\n.\r\n结束。
\r\n是换行的意思,但是要注意是用\r\n换行,不是用\n换行。

填写正文
输入1

上面的Subject表示主题,即邮箱的标题,To是收件人,From是发件人,Content-Type是类型,charset是编码,Content-Transfer-Encoding是内容转移编码。具体参数都可以是什么请自行百度。到真正的正文的之前要空一行。如果你的内容里要出现\r\n.\r\n,请替换成\r\n…\r\n。其他冲突的解决方法请自行百度。

输入2

250是成功的状态码。
250 Ok: queued as
表示发送成功了(qq邮箱smtp服务器发送成功的反馈是这个,别的服务器不一定,但250是一定会有的)。

退出连接
退出1
退出2

完整的交互文本(除了我把我的密码隐藏了,其他的都是完整的):

连接到服务器

服务器:
220 smtp.qq.com Esmtp QQ Mail Server

我:
EHLO smtp.qq.com

服务器:
250-smtp.qq.com
250-PIPELINING
250-SIZE 73400320
250-STARTTLS
250-AUTH LOGIN PLAIN
250-AUTH=LOGIN
250-MAILCOMPRESS
250 8BITMIME

我:
AUTH LOGIN

服务器:
334 VXNlcm5hbWU6

我:
NzcxNzc4MDg3QHFxLmNvbQ==

服务器:
334 UGFzc3dvcmQ6

我:
我怎么能在这里公开我的密码呢

服务器:
235 Authentication successful

我:
MAIL FROM: <771778087@qq.com>

服务器:
250 Ok

我:
RCPT TO: <771778087@qq.com>

服务器:
250 Ok

我:
DATA

服务器:
354 End data with <CR><LF>.<CR><LF>

我:
Subject:=?utf-8?B?5rWL6K+V?=
To: 771778087@qq.com
From: 771778087@qq.com <771778087@qq.com>
Content-Type: text/plain; charset=UTF8;
Content-Transfer-Encoding: 7BIT

这是一封测试邮件。
.

服务器:
250 Ok: queued as 

我:
QUIT

服务器:
221 Bye

与服务器断开连接

收到的邮件:
邮件

封装成ZSmtp类

  在这部分我不想再多作任何的解释,把前面都看明白了这部分不需要看,自己就可以封装了。如果你急着用发邮件功能,那就复制下面的代码(只封装了发送纯文本的功能):

下面实现的类的类名是以Z开头的,这是在模仿Qt,Qt库自带的类都是以Q开头的,我的名字拼音首字母是Z所以我写的类以Z开头。
前面内容没看的注意一下,发送邮件的邮箱一定要开启smtp服务,否则是无法发送邮件的。

ZSmtp类代码

zsmtp.h

#ifndef ZSMTP_H
#define ZSMTP_H

#include <QObject>
#include <QTcpSocket>

#define EMAIL_ERROR     0   //邮件发送失败
#define EMAIL_SUCCEED   1   //邮件发送成功

class ZSmtp : public QObject
{
    Q_OBJECT
public:
    explicit ZSmtp(QString serverIP = "smtp.qq.com", QObject *parent = NULL);
    ~ZSmtp();
    void sendEmail(QString username, QString password, QString to, QString title, QString text, QString ip = "");

private:
    QString serverIP;
    QTcpSocket *tcpSocket;
    QString username;
    QString password;
    QString to;
    QString title;
    QString text;
    QByteArray serverText;
    int status;

signals:
    void disconnected();
    void emailStatus(int status);   //邮件发送的状态
    void progress(double p);

public slots:
    void connectToServer();
    void disconnectFromServer();
    void getMessage();

    void sendEmailSlot(QString username, QString password, QString to, QString title, QString text);

};

#endif // ZSMTP_H

zsmtp.cpp

#include "zsmtp.h"
#include <QDebug>

ZSmtp::ZSmtp(QString serverIP, QObject *parent) : QObject(parent)
{
    this->serverIP = serverIP;
    tcpSocket = new QTcpSocket;
    connect(tcpSocket, SIGNAL(connected()), this, SLOT(connectToServer()));
    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(disconnectFromServer()));
    connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(getMessage()));
    qDebug()<<"ZSmtp";
}

ZSmtp::~ZSmtp()
{
    delete tcpSocket;
    qDebug()<<"~ZSmtp";
}

void ZSmtp::sendEmail(QString username, QString password, QString to, QString title, QString text, QString ip)
{
    if(ip != "")
    {
        serverIP = ip;
    }
    this->username = username;
    this->password = password;
    this->to = to;
    this->title = title;
    this->text = text;
    tcpSocket->abort();
    serverText.clear();
    status = 0;
    tcpSocket->connectToHost(serverIP, 25);
}

void ZSmtp::connectToServer()
{
    qDebug()<<"connect to server";
}

void ZSmtp::disconnectFromServer()
{
    qDebug()<<"disconnect from server";
    emit disconnected();
}

#define STATUS_MAX 6
void ZSmtp::getMessage()
{
    QByteArray curText = tcpSocket->readAll();
    serverText.append(curText);
    QByteArray text;
    //qDebug()<<curText;
    if(serverText.indexOf("Error")!=-1 || serverText.indexOf("503")!=-1)
    {
        //出错了
        qDebug()<<"get the Error message";
        emit emailStatus(EMAIL_ERROR);
        tcpSocket->disconnectFromHost();
        return ;
    }
    if(status==5 && serverText.indexOf("250")!=-1)
    {
        //登出
        text.append("QUIT\r\n");
        status = 6;
    }
    else if(status==4 && serverText.indexOf("354")!=-1)
    {
        //发信息
        text.append("Subject:=?utf-8?B?");
        text.append(QByteArray().append(title).toBase64());
        text.append("?=\r\n");
        text.append("To: ");
        text.append(to);
        text.append("\r\nFrom: ");
        text.append(username);
        text.append(" <");
        text.append(username);
        text.append(">\r\n");
        text.append("Content-Type: text/plain; charset=UTF8;\r\n");
        text.append("Content-Transfer-Encoding: 7BIT\r\n\r\n");
        QString t = this->text;
        t.replace("\n", "\r\n").replace("\r\n.\r\n", "\r\n..\r\n");
        text.append(t);
        text.append("\r\n.\r\n");
        status = 5;
    }
    else if(status==3 && serverText.indexOf("250")!=-1)
    {
        //DATA
        text.append("DATA\r\n");
        status = 4;
    }
    else if(status==2 && serverText.indexOf("235")!=-1)
    {
        //发送方和接收方
        text.append("MAIL FROM: <");
        text.append(username);
        text.append(">\r\n");
        text.append("RCPT TO: <");
        text.append(to);
        text.append(">\r\n");
        status = 3;
    }
    else if(status==1 && serverText.indexOf("334")!=-1)
    {
        //登录
        text.append(QByteArray().append(username).toBase64());
        text.append("\r\n");
        text.append(QByteArray().append(password).toBase64());
        text.append("\r\n");
        status = 2;
    }
    else if(status==0 && serverText.indexOf("220")!=-1)
    {
        //打招呼
        text.append("EHLO ");
        text.append(serverIP);
        text.append("\r\nAUTH LOGIN\r\n");
        status = 1;
    }
    tcpSocket->write(text);
    //qDebug()<<text;
    emit progress((double)status/STATUS_MAX);   //进度
    if(status == 6)
    {
        emit emailStatus(EMAIL_SUCCEED);
        tcpSocket->disconnectFromHost();
    }
}

void ZSmtp::sendEmailSlot(QString username, QString password, QString to, QString title, QString text)
{
    sendEmail(username, password, to, title, text);
}

ZSmtp类用法说明

  首先要在你的项目的.pro文件里加上:

QT       += network

  然后是在你想要用发邮件功能的地方写上:

ZSmtp *smtp = new ZSmtp;//默认是qq邮箱服务器,想用别的服务器就 new ZSmtp(Smtp服务器地址)
connect(smtp, SIGNAL(disconnected()), smtp, SLOT(deleteLater()));	//发送完毕自行销毁
smtp->sendEmail(发送邮箱号, 发送邮箱密码, 接收邮箱号, 邮件标题, 邮件内容);
//上面的参数都不需要转换为base64,直接写原文本就可以了

  进一步,如果你想得到邮件的发送状态(成功或者失败),就这样写:

void YourClass::yourSlot(int status)
{
	if(status == EMAIL_SUCCEED)	//邮件发送成功
	{
		//do something
	}
	else if(status == EMAIL_ERROR)	
	{//邮件发送失败(原因可能是发、收件人邮箱号写错了,smtp服务器崩了等)
		//do something
	}
}
......
//下面是要使用发送邮件功能的地方
ZSmtp *smtp = new ZSmtp;
connect(smtp, SIGNAL(emailStatus(int)), this, SLOT(yourSlot(int)));
connect(smtp, SIGNAL(disconnected()), smtp, SLOT(deleteLater()));
smtp->sendEmail(发送邮箱号, 发送邮箱密码, 接收邮箱号, 邮件标题, 邮件内容);

  如果你还想获得邮件发送的进度,就这样写:

void YourClass::yourSlot(double p)	//这个p就是进度,范围是0到1
{
	//do something
}
......
//下面是要使用发送邮件功能的地方
ZSmtp *smtp = new ZSmtp;
connect(smtp, SIGNAL(progress(double)), this, SLOT(yourSlot(double)));
connect(smtp, SIGNAL(disconnected()), smtp, SLOT(deleteLater()));
smtp->sendEmail(发送邮箱号, 发送邮箱密码, 接收邮箱号, 邮件标题, 邮件内容);

  这个ZSmtp类是不会卡死线程的,因为它是通过信号槽来接收服务器的消息的,所以不会出现使用堵塞线程的方法来获取服务器消息卡死线程的情况。但是如果你仍然想用多线程来发邮件也是可以的:

//在.h里添加一个信号
signals:
void sendEmailSignal(QString username, QString password, 
					QString to, QString title, QString text);
......
//下面是要使用发送邮件功能的地方
ZSmtp *smtp = new ZSmtp;
QThread *thread = new QThread;
smtp->moveToThread(thread);
connect(this, 
	SIGNAL(sendEmailSignal(QString,QString,QString,QString,QString)), 
	smtp, 
	SLOT(sendEmailSlot(QString,QString,QString,QString,QString)));
connect(smtp, SIGNAL(disconnected()), smtp, SLOT(deleteLater()));
connect(smtp, SIGNAL(destroyed()), thread, SLOT(quit()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
emit sendEmailSignal(发送邮箱号, 发送邮箱密码, 接收邮箱号, 邮件标题, 邮件内容);

  现在就可以随意发送邮件了。

注:163邮箱的smtp服务器地址是:smtp.163.com,端口和qq邮箱端口一样是25。基本上smtp服务器的端口都是25。
端口是25会引发一个问题:如果你是使用云端服务器等服务器连接到smtp服务器发邮件,可能会出现无法发送的情况,因为你的云服务器可能默认是禁用25端口的,如果要在你的云服务器开启25端口请与服务器管理人员联系开启。

  • 12
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
发送邮件需要使用SMTP协议,可以使用C++编写SMTP客户端实现邮件发送功能。下面是一个使用C++实现SMTP发送邮件的示例代码: ```c++ #include <iostream> #include <winsock2.h> #include <ws2tcpip.h> #pragma comment(lib, "Ws2_32.lib") using namespace std; int main() { // 初始化Winsock库 WSADATA wsaData; if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { cout << "Failed to initialize Winsock library." << endl; return 1; } // 创建套接字 SOCKET sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { cout << "Failed to create socket." << endl; WSACleanup(); return 1; } // 获取SMTP服务器的IP地址 struct addrinfo* result = NULL, hints; ZeroMemory(&hints, sizeof(hints)); hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_protocol = IPPROTO_TCP; if (getaddrinfo("smtp.example.com", "25", &hints, &result) != 0) { cout << "Failed to get SMTP server IP address." << endl; closesocket(sock); WSACleanup(); return 1; } // 连接SMTP服务器 if (connect(sock, result->ai_addr, (int)result->ai_addrlen) != 0) { cout << "Failed to connect to SMTP server." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的欢迎信息 char recvbuf[1024]; int recvbuflen = 1024; if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive welcome message from SMTP server." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 发送EHLO命令 const char* ehlo = "EHLO example.com\r\n"; if (send(sock, ehlo, (int)strlen(ehlo), 0) <= 0) { cout << "Failed to send EHLO command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的响应 if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive response to EHLO command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 发送AUTH LOGIN命令 const char* auth = "AUTH LOGIN\r\n"; if (send(sock, auth, (int)strlen(auth), 0) <= 0) { cout << "Failed to send AUTH LOGIN command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的响应 if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive response to AUTH LOGIN command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 发送用户名 const char* username = "your_email@example.com"; int len = (int)strlen(username); for (int i = 0; i < len; i++) { username[i] = base64_encode(username[i]); } const char* user = username; if (send(sock, user, (int)strlen(user), 0) <= 0) { cout << "Failed to send username." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } if (send(sock, "\r\n", 2, 0) <= 0) { cout << "Failed to send CRLF." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的响应 if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive response to username." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 发送密码 const char* password = "your_password"; len = (int)strlen(password); for (int i = 0; i < len; i++) { password[i] = base64_encode(password[i]); } const char* pass = password; if (send(sock, pass, (int)strlen(pass), 0) <= 0) { cout << "Failed to send password." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } if (send(sock, "\r\n", 2, 0) <= 0) { cout << "Failed to send CRLF." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的响应 if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive response to password." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 发送MAIL FROM命令 const char* mailfrom = "MAIL FROM:<your_email@example.com>\r\n"; if (send(sock, mailfrom, (int)strlen(mailfrom), 0) <= 0) { cout << "Failed to send MAIL FROM command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的响应 if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive response to MAIL FROM command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 发送RCPT TO命令 const char* rcptto = "RCPT TO:<recipient_email@example.com>\r\n"; if (send(sock, rcptto, (int)strlen(rcptto), 0) <= 0) { cout << "Failed to send RCPT TO command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的响应 if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive response to RCPT TO command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 发送DATA命令 const char* data = "DATA\r\n"; if (send(sock, data, (int)strlen(data), 0) <= 0) { cout << "Failed to send DATA command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的响应 if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive response to DATA command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 发送邮件内容 const char* content = "From: your_email@example.com\r\n" "To: recipient_email@example.com\r\n" "Subject: Test\r\n" "\r\n" "This is a test email.\r\n" ".\r\n"; if (send(sock, content, (int)strlen(content), 0) <= 0) { cout << "Failed to send email content." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的响应 if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive response to email content." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 发送QUIT命令 const char* quit = "QUIT\r\n"; if (send(sock, quit, (int)strlen(quit), 0) <= 0) { cout << "Failed to send QUIT command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } // 接收服务器的响应 if (recv(sock, recvbuf, recvbuflen, 0) <= 0) { cout << "Failed to receive response to QUIT command." << endl; freeaddrinfo(result); closesocket(sock); WSACleanup(); return 1; } cout << recvbuf << endl; // 关闭套接字 freeaddrinfo(result); closesocket(sock); // 关闭Winsock库 WSACleanup(); return 0; } // Base64编码 char base64_encode(char c) { if (c >= 'A' && c <= 'Z') { return c - 'A'; } else if (c >= 'a' && c <= 'z') { return c - 'a' + 26; } else if (c >= '0' && c <= '9') { return c - '0' + 52; } else if (c == '+') { return 62; } else if (c == '/') { return 63; } else { return -1; } } ``` 上面的代码使用了Windows Sockets API来实现SMTP客户端,需要在Windows系统下编译运行。在代码中,需要将"smtp.example.com"和"your_email@example.com"替换为实际的SMTP服务器地址和发件人邮箱地址。另外,需要在代码中指定收件人邮箱地址、邮件主题和邮件内容。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值