You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
p2l5wexnu/data/ch_socket/sec_smtp.tex

178 lines
7.7 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

%# -*- coding: utf-8-unix -*-
\section{SMTP客户端实现}
\label{sec:c:socket:s:smtp}
\subsection{实验目的}
\label{subsec:c:socket:s:smtp_object}
进一步理解和掌握基于Python进行TCP套接字编程的知识
理解SMTP报文格式能基于Python编写一个简单的SMTP客户端程序。
\subsection{实验内容}
\label{subsec:c:socket:s:smtp_content}
通过Python编写代码创建一个可以向标准电子邮件地址发送电子邮件的简单邮件客户端。
该客户端可以与邮件服务器创建一个TCP连接
并基于SMTP协议与邮件服务器交互并发送邮件报文
完成邮件发送后关闭连接。
\subsection{实验原理、方法和手段}
\label{subsec:c:socket:s:smtp_principle}
简单邮件传输协议Simple Mail Transfer ProtocolSMTP
是实现电子邮件收发的主要应用层协议它基于TCP提供的可靠数据传输连接
从发送方的邮件服务器向接收方的邮件服务器发送邮件。
注意,虽然一般情况下邮件总是从发送方的邮件服务器中发出,
但是工作在发送方邮件服务器上的发送程序是一个SMTP客户端
因此一个完整的SMTP程序总有两个部分参与工作
运行在发送方邮件服务器的SMTP客户端和运行在接收方邮件服务器的SMTP服务器。
SMTP是一个古老的应用层协议
1982年在RFC文档 \href{https://tools.ietf.org/html/rfc821}{821}
中首次被定义,
然后在2001和2008年进行了两次更新
分别为RFC \href{https://tools.ietf.org/html/rfc2821}{2821}
和RFC \href{https://tools.ietf.org/html/rfc5321}{5321}
因此虽然SMTP拥有众多出色的性质但也遗留了一些陈旧特征
例如它限制所有邮件报文的主体部分只能采用简单的7比特ASCII码表示。
所以在用SMTP传送邮件之前需要将二进制数据编码为ASCII码
在传输后再进行解码还原为二进制数据
\footnote{SMTP存在一些服务扩展定义
例如RFC \href{https://tools.ietf.org/html/rfc3030}{3030}
就定义了如何采用非ASCII的方式传送二进制数据}
假设存在一个发送方邮件服务器主机名为company.com
而对应的接收方邮件服务器的主机名为network.net。
SMTP客户端要从地址alice@company.com向地址bob@network.net发送报文
\texttt{Do you like ketchupHow about pickles}
以下流程展示了运行在发送方邮件服务器上的SMTP客户端C
和运行在接收方邮件服务器上的SMTP服务器S之间交换SMTP报文文本的实际通信过程
\begin{code}[text]
S: 220 network.net
C: HELO company.com
S: 250 Hello company.com, pleased to meet you
C: MAIL FROM:<alice@company.com>
S: 250 alice@company.com... Sender ok
C: RCPT TO:<bob@network.net>
S: 250 bob@network.net... Recipient ok
C: DATA S:354 Enter mail, end with "."on a line by itself
C: Do you like ketchup?
C: How about pickles?
C: .
S: 250 Message accepted for delivery
C: QUIT
S: 221 network.net closing connection
\end{code}
注意:以\texttt{C:}开头的ASCII码文本行是SMTP客户端通过TCP套接字发出的消息
而以\texttt{S:}开头的ASCII码则是SMTP服务器通过TCP套接字发出的消息。
在这个例子中SMTP客户端发送了5条命令
\texttt{HELO}是HELLO的缩写\texttt{MAIL FROM}
\texttt{RCPT TO}\texttt{DATA}以及\texttt{QUIT}
这些命令都是自解释的,可以简单通过其英文含义理解。
在具体消息内容部分,客户端通过发送一个只包含一个句点的行向服务器指示消息内容的结束
注意在实际传输时报文在结尾处会包含两个额外的不可打印字符“0x0A”与“0x0D”。
分别表示回车“CR”和换行“LF”
服务器对客户端发出的每条命令都做出了回答,
其中每个回答含有一个回答码和一些英文解释,
其中的英文解释内容在实际使用时是可选的。
有一点需要注意由于SMTP使用的是TCP连接所以可以复用一个连接发送多封邮件。
在这种情况下,发送方在完成握手后会连续发送所有这些邮件,
对每个邮件,客户端用一个新的\texttt{MAIL FROM:<???@company.com>}开始,
并用一个独立的句点指示该邮件的结束,
然后在所有邮件发送完后才发送QUIT结束一次与服务器的连接。
\subsection{实验条件}
\label{subsec:c:socket:s:smtp_requirement}
\begin{itemize}
\item 装有python环境的电脑一台
\item 已经正常运行的邮件服务器开启非加密模式的SMTP支持
\item 部分代码(\nameref{subsec:c:socket:s:smtp_additional}中已给出);
\item Python语言参考手册 -- TCP部分\footnote{可以参考Python3官方手册的
\href{https://docs.python.org/zh-cn/3/library/socket.html}
{套接字}部分,也可以查询其他相关手册}
\item SMTP协议参考手册
\footnote{可以参考SMTP的\href{https://tools.ietf.org/html/rfc5321}{RFC文档}
也可以查询其他相关手册}
\end{itemize}
\subsection{实验步骤}
\label{subsec:c:socket:s:smtp_procedure}
本实验\nameref{subsec:c:socket:s:smtp_additional}
一节中展示了一段SMTP客户端的框架代码
学生需要逐步填充代码中不完善的部分,完成一个简单电子邮件客户端程序,
并通过向不同的账号发送电子邮件来测试程序。
\subsection{进阶任务}
\label{subsec:c:socket:s:smtp_rethink}
阅读相关文档,修改代码,使编写的程序可以发送包含图片等二进制数据的电子邮件。
\subsection{注意事项及有关说明}
\label{subsec:c:socket:s:smtp_notice}
由于SMTP协议较为传统因此部分公开的邮件服务器默认情况下关闭了SMTP支持
有些邮件服务器为了安全只支持工作在TLS安全连接上的SMTP。
因此为了方便测试请选择支持非加密SMTP连接的服务器进行测试
如果选择自行搭建SMTP服务器进行测试
则需注意在设置中开启SMTP协议并保证其工作在非TLS加密模式下。
\subsection{考核方法}
\label{subsec:c:socket:s:smtp_criterion}
本实验需提交一份实验报告和编写的代码文件。报告内容应当包括以下三个部分:
\begin{itemize}
\item 代码的说明;
\item 不同环境下代码运行的结果;
\item 对结果的分析和总结体会。
\end{itemize}
本实验评分标准:
\begin{enumerate}
\item 规定时间内完成实验报告20分
\item 代码正确运行20分不能正常运行0分
\item 实验报告格式整洁20分
\item 实验报告中详细记录了实验过程在实验中所遇到的问题以及解决方法20分
\item 实验报告中仔细分析了实验结果并能提出自己的改进措施20分。
\end{enumerate}
\subsection{附件}
\label{subsec:c:socket:s:smtp_additional}
基于Python的SMTP客户端框架程序
\begin{code}[python]
from socket import *
msg = "\r\n I love computer networks!"
endmsg = "\r\n.\r\n"
# 选择一个邮件服务器
mailserver = #按需补充
# 创建socket和邮件服务器建立TCP连接
recv = clientSocket.recv(1024)
print(recv)
if recv[:3] != '220':
print '220 reply not received from server.'
# 发送HELO命令打印服务器响应。
heloCommand = 'HELO Alice\r\n'
clientSocket.send(heloCommand)
recv1 = clientSocket.recv(1024)
print((recv1)
if recv1[:3] != '250':
print ('250 reply not received from server.')
# 发送MAIL FROM命令打印服务器响应。
# 发送RCPT TO命令打印服务器响应。
# 发送DATA命令打印服务器响应。
# 发送邮件内容。
# 消息以单个"."结束。
# 发送QUIT命令获取服务器响应。
\end{code}