服务器smtp协议,SMTP协议解析

http://home.eeworld.com.cn/my/space-uid-361439-blogid-360809.html

2016在写这篇帖子之前发表过一篇讨论SMTP实现的帖子,大伙的反馈还是挺热烈的,今天就说说SMTP到底是干嘛的。

首先来个官方对于SMTP协议的介绍:

SMTP(Simple Mail Transfer Protocol)即。它使用由TCP提供的可靠的数据传输服务把邮件消息从发信人的邮件服务器传送到收信人的邮件服务器。跟大多数应用层协议一样,SMTP也存在两个 端:在发信人的邮件服务器上执行的客户端和在收信人的邮件服务器上执行的服务器端。SMTP的客户端和服务器端同时运行在每个邮件服务器上。当一个邮件服 务器在向其他邮件服务器发送邮件消息时,它是作为SMTP客户在运行。SMTP协议与人们用于面对面交互的礼仪之间有许多相似之处。首先,运行在发送端邮件服务器主机上的SMTP客户,发起建立一个到运行在接收端邮件服务 器主机上的SMTP服务器端口号25之间的TCP连接。如果接收邮件服务器当前不在工作,SMTP客户就等待一段时间后再尝试建立该连接。SMTP客户和服务器先执行一些应用层握手操作。就像人们在转手东西之前往往先自我介绍那样,SMTP客户和服务器也在传送信息之前先自我介绍一下。 在这个SMTP握手阶段,SMTP客户向服务器分别指出发信人和收信人的电子邮件地址。彼此自我介绍完毕之后,客户发出邮件消息,具体的介绍可以看我之前发的链接 http://home.eeworld.com.cn/my/space-uid-361439-blogid-343574.html

上面讲了那么多,其实SMTP就是一种

HELO;识别发送方到接收SMTP的一个HELLO命令

MAIL FROM:;为发送者地址。此命令告诉接收方一个新邮件发送的开始,并对所有的状态和缓冲区进行初始化。此命令开始一个邮件传输处理,最终完成将邮件到一个或多个邮箱中。

RCPT TO:;标识各个接收者的地址

DATA

接收SMTP将把其后的行为看作邮件数据去处理,以.;标识数据的结尾。

REST;退出/复位当前的邮件传输

NOOP;要求接收SMTP仅做OK应答。(用于测试)

QUIT;要求接收SMTP返回一个OK应答并关闭传输。

VRFY;验证指定的邮箱是否存在,由于安全因素,多禁止此命令。

EXPN;验证给定的邮箱列表是否存在,扩充邮箱列表,也常禁止使用。

HELP;查询服务器支持什么命令

没错,其实看起来很高大上的发送邮件邮件就是通过上面几条命令来实现的,现在我们拿Telnet来实现上面的功能:对于邮件服务器的端口如果不带SSL功能默认是25.下面我就拿新浪邮箱来做个简单的测试:

1:用telnet实现发送单封邮件功能,发送邮件的流程如下:

下面实现通过一个新浪邮箱向我QQ发送一个消息功能

75701303_1.png

也是大伙对于上面的应答码看不明白,可以看下我之前发的SMTP应答码解释

75701303_2.png

2:那如何实现一对多的模式发送邮件呢?

其实只要多次调用RCPT TO:;这条命令就行

75701303_3.png

75701303_4.png

对于ESP8266里面实现的WIFI邮件功能,其实就是将命令组合起来调用而已:

其实SMTP就是那么简单,要实现发送邮件的功能也就是上面几条命令而已,技术就是这样懂得永远觉得简单,不懂的永远觉得那么难,一下就到11点了,实现了SMTP协议也仅仅是实现了发送邮件功能,如果你想实现离线下载邮件,那就不得不提POP3协议了,由于时间原因,明晚继续~~~~~~~~~~~~~~~~

最后温馨提醒:CRLF是\r\n,在调试SMTP时,之前一直出现失败,主要原因是邮件服务器把邮件当作垃圾邮件处理了导致无法发送成功,所以大伙主要发送的主题不要随便写,尽量规避掉服务器的约束~~~~~~~~·~~~~

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该压缩包包含三个文档,分别是SMTP协议详解,POP3协议详解,MIME规范详解,文档中详细介绍了一个邮件发送和接收的过程分析,协议本身的包含的命令和工作过程,为开发邮件代理的客户端提供技术基础。如下是部分SMTP协议部分内容: 1.1 SMTP在邮件通信中的位置 SMTP,即简单邮件传送协议,所对应RFC文档为RFC821。同http等多数应用层协议一样,它工作在C/S模式下,用来实现因特网上的邮件传送。SMTP在整个电子邮件通信中所处的位置。可以看出,SMTP是用来将客户机上的邮件传送到服务器上。这里的客户机是指某次连接中的发送方,服务器是指相应的接收方。在讲解发送邮件的整个通信过程前,先解释一下面几个术语。 1.2几个术语 1.2.1.邮件 邮件是一种消息的格式,由信封、首部和正文组成。 信封上最重要的是收信人的地址。邮件服务器用这个地址将邮件发送到收信人所在的邮件服务器上。 首部是由用户代理或邮件服务器添加的一些信息。包括Received、Message-ID、From、Data、Reply-To、X-Phone、X-Mailer、To和Subject等字段。 正文是是发送用户发给接收用户报文的内容。RFC 822 规定正文为NVT ASCII文字行。 更为详细的说明,请参考RFC821和RFC822等协议。 1.2.2.用户代理 用户代理UA(User Agent)是用户与电子邮件系统的交互接口,一般来说它就是我们PC机上的一个程序。Windows上常见的用户代理是Foxmail和Outlook Express。 用户代理提供一个好的用户界面,它提取用户在其界面填写的各项信息,生成一封符合SMTP等邮件标准的邮件,然后采用SMTP协议将邮件发送到发送端邮件服务器
以下是用C语言封装SMTP协议的示例代码(仅供参考): ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netdb.h> #include <unistd.h> #define BUFFER_SIZE 1024 void send_command(int sockfd, const char* command, const char* args) { char buffer[BUFFER_SIZE]; snprintf(buffer, BUFFER_SIZE, "%s %s\r\n", command, args); send(sockfd, buffer, strlen(buffer), 0); } int recv_response(int sockfd) { char buffer[BUFFER_SIZE]; int n = recv(sockfd, buffer, BUFFER_SIZE - 1, 0); if (n < 0) { perror("recv"); return -1; } buffer[n] = '\0'; printf("%s", buffer); return atoi(buffer); } int send_mail(const char* server, const char* from, const char* to, const char* subject, const char* body) { struct hostent* host = gethostbyname(server); if (host == NULL) { printf("Unknown host: %s\n", server); return -1; } int sockfd = socket(AF_INET, SOCK_STREAM, 0); if (sockfd < 0) { perror("socket"); return -1; } struct sockaddr_in server_addr; memset(&server_addr, 0, sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(25); server_addr.sin_addr = *((struct in_addr*) host->h_addr); if (connect(sockfd, (struct sockaddr*) &server_addr, sizeof(server_addr)) < 0) { perror("connect"); return -1; } recv_response(sockfd); // 220 send_command(sockfd, "HELO", server); if (recv_response(sockfd) != 250) { printf("Failed to send HELO\n"); return -1; } send_command(sockfd, "MAIL FROM:", from); if (recv_response(sockfd) != 250) { printf("Failed to send MAIL FROM\n"); return -1; } send_command(sockfd, "RCPT TO:", to); if (recv_response(sockfd) != 250) { printf("Failed to send RCPT TO\n"); return -1; } send_command(sockfd, "DATA", ""); if (recv_response(sockfd) != 354) { printf("Failed to send DATA\n"); return -1; } send_command(sockfd, "Subject:", subject); send_command(sockfd, "From:", from); send_command(sockfd, "To:", to); send_command(sockfd, "", ""); send_command(sockfd, body, ""); send_command(sockfd, ".", ""); if (recv_response(sockfd) != 250) { printf("Failed to send .\n"); return -1; } send_command(sockfd, "QUIT", ""); if (recv_response(sockfd) != 221) { printf("Failed to send QUIT\n"); return -1; } close(sockfd); return 0; } int main(int argc, char* argv[]) { if (argc < 6) { printf("Usage: %s server from to subject body\n", argv[0]); return -1; } const char* server = argv[1]; const char* from = argv[2]; const char* to = argv[3]; const char* subject = argv[4]; const char* body = argv[5]; return send_mail(server, from, to, subject, body); } ``` 这个示例代码实现了一个简单的SMTP客户端,可以向指定的服务器发送邮件。具体步骤如下: 1. 解析服务器的IP地址 2. 创建TCP连接并发送HELO命令 3. 发送MAIL FROM命令 4. 发送RCPT TO命令 5. 发送DATA命令 6. 发送邮件头和正文 7. 发送.命令 8. 发送QUIT命令 在实际使用中,需要根据具体的SMTP服务器要求修改代码。例如,有些服务器需要验证用户名和密码,需要在发送MAIL FROM命令之前发送AUTH LOGIN命令。另外,需要注意邮件正文中的换行符应该使用\r\n,而不是\n。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值