Tutorial on using Python poplib module and smtplib module to send and receive emails

WBOY
Release: 2016-07-22 08:56:32
Original
1239 people have browsed it

poplib module receives emails
Python’s poplib module is used to receive emails from pop3. It can also be said that it is the first step in processing emails.
The POP3 protocol is not complicated. It also uses a question-and-answer method. If you send a command to the server, the server will definitely reply with a message. The pop3 command code is as follows:

命令 poplib方法  参数    状态     描述
-----------------------------------------------------------------------------------------------
USER  user   username  认可  用户名,此命令与下面的pass命令若成功,将导致状态转换
PASS  pass_   password  认可  用户密码   
APOP  apop   Name,Digest 认可  Digest是MD5消息摘要
-----------------------------------------------------------------------------------------------
STAT  stat   None    处理  请求服务器发回关于邮箱的统计资料,如邮件总数和总字节数
UIDL  uidl   [Msg#]   处理  返回邮件的唯一标识符,POP3会话的每个标识符都将是唯一的
LIST  list   [Msg#]   处理  返回邮件数量和每个邮件的大小
RETR  retr   [Msg#]   处理  返回由参数标识的邮件的全部文本
DELE  dele   [Msg#]   处理  服务器将由参数标识的邮件标记为删除,由quit命令执行
RSET  rset   None    处理  服务器将重置所有标记为删除的邮件,用于撤消DELE命令
TOP   top    [Msg#]   处理  服务器将返回由参数标识的邮件前n行内容,n必须是正整数
NOOP  noop   None    处理  服务器返回一个肯定的响应
----------------------------------------------------------------------------------------------
QUIT  quit   None    更新    
Copy after login

Python’s poplib also provides corresponding methods for these commands, which are marked in the second column. The process of receiving emails is generally:
1. Connect to pop3 server (poplib.POP3.__init__)
2. Send username and password for verification (poplib.POP3.user poplib.POP3.pass_)
3. Get the mail information in the mailbox (poplib.POP3.stat)
4. Receive emails (poplib.POP3.retr)
5. Delete emails (poplib.POP3.dele)
6. Quit (poplib.POP3.quit)
Note that what I wrote in parentheses above is the method to use to complete this operation. You cannot write it like that in the actual code. You should create an object of poplib.POP3 and then call the method of this object. For example:

poplib.POP3.quit 
Copy after login

should be understood as

a = poplib.POP3(host)
a.quit()
Copy after login

Look at the actual code below:

#-*- encoding: gb2312 -*-
import os, sys, string
import poplib

# pop3服务器地址
host = "pop3.163.com"
# 用户名
username = "xxxxxx@163.com"
# 密码
password = "xxxxxxx"
# 创建一个pop3对象,这个时候实际上已经连接上服务器了
pp = poplib.POP3(host)
# 设置调试模式,可以看到与服务器的交互信息
pp.set_debuglevel(1)
# 向服务器发送用户名
pp.user(username)
# 向服务器发送密码
pp.pass_(password)
# 获取服务器上信件信息,返回是一个列表,第一项是一共有多上封邮件,第二项是共有多少字节
ret = pp.stat()
print ret
# 需要取出所有信件的头部,信件id是从1开始的。
for i in range(1, ret[0]+1):
  # 取出信件头部。注意:top指定的行数是以信件头为基数的,也就是说当取0行,
  # 其实是返回头部信息,取1行其实是返回头部信息之外再多1行。
  mlist = pp.top(i, 0)
  print 'line: ', len(mlist[1])
# 列出服务器上邮件信息,这个会对每一封邮件都输出id和大小。不象stat输出的是总的统计信息
ret = pp.list()
print ret
# 取第一封邮件完整信息,在返回值里,是按行存储在down[1]的列表里的。down[0]是返回的状态信息
down = pp.retr(1)
print 'lines:', len(down)
# 输出邮件
for line in down[1]:
  print line
# 退出
pp.quit()

Copy after login

In some places, it is said that secure email is actually SSL encryption for pop3. In this way, poplib can also handle it, but instead of using the POP3 class, it uses POP3_SSL. Their methods are the same. Therefore, to support SSL, in the above code, replace the line that creates the pop3 object:

pp = poplib.POP3_SSL(host)
Copy after login

smtplib: Send SSL/TLS secure email using python
Python's smtplib provides a very convenient way to send emails. It simply encapsulates the SMTP protocol.
The basic commands of the smtp protocol include:

  • HELO identifies the user to the server
  • MAIL Initialize mail transfer mail from:
  • RCPT identifies a single email recipient; often behind the MAIL command, there can be multiple rcpt to:
  • DATA After single or multiple RCPT commands, it indicates that all email recipients have been identified and data transmission is initiated, ending with.
  • VRFY is used to verify whether the specified user/mailbox exists; due to security reasons, servers often prohibit this command
  • EXPN verifies whether the given mailbox list exists, expands the mailbox list, and is often disabled
  • HELP Query what commands the server supports
  • NOOP No operation, the server should respond OK
  • QUIT End session
  • RSET resets the session, the current transfer is canceled
  • MAIL FROM Specified sender address
  • RCPT TO specified recipient address

Generally, there are two methods for SMTP sessions. One is direct mail delivery, that is, if you want to send an email to zzz@163.com, then directly connect to the mail server of 163.com and send the letter to zzz@ 163.com; The other is to send an email after verification. The process is, for example, if you want to send an email to zzz@163.com, you do not send it directly to 163.com, but through another email on sina.com. Send via email. In this way, you need to first connect to the SMTP server of sina.com, then authenticate, and then submit the letter to 163.com to sina.com, and sina.com will help you deliver the letter to 163.com.

The command flow of the first method is basically as follows:
1. helo
2. mail from
3. rcpt to
4. data
5. quit
But the first sending method generally has limitations, that is, the email recipient specified by rcpt to must exist on this server, otherwise it will not be received. Let’s take a look at the code first:

#-*- encoding: gb2312 -*-
import os, sys, string
import smtplib

# 邮件服务器地址
mailserver = "smtp.163.com"
# smtp会话过程中的mail from地址
from_addr = "asfgysg@zxsdf.com"
# smtp会话过程中的rcpt to地址
to_addr = "zhaoweikid@163.com"
# 信件内容
msg = "test mail"

svr = smtplib.SMTP(mailserver)
# 设置为调试模式,就是在会话过程中会有输出信息
svr.set_debuglevel(1)
# helo命令,docmd方法包括了获取对方服务器返回信息
svr.docmd("HELO server")
# mail from, 发送邮件发送者
svr.docmd("MAIL FROM: <%s>" % from_addr)
# rcpt to, 邮件接收者
svr.docmd("RCPT TO: <%s>" % to_addr)
# data命令,开始发送数据
svr.docmd("DATA")
# 发送正文数据
svr.send(msg)
# 比如以 . 作为正文发送结束的标记,用send发送的,所以要用getreply获取返回信息
svr.send(" . ")
svr.getreply()
# 发送结束,退出
svr.quit()

Copy after login

Note that 163.com has an anti-spam function. The above method of delivering emails may not pass the detection of the anti-spam system. Therefore, it is generally not recommended for individuals to send in this way.
The second one is a little different:
1.ehlo
2.auth login
3.mail from
4.rcpt to
5.data
​ 6.quit
Compared with the first one, there is one more authentication process, which is the auth login process.

#-*- encoding: gb2312 -*-
import os, sys, string
import smtplib
import base64

# 邮件服务器地址
mailserver = "smtp.163.com"
# 邮件用户名
username = "xxxxxx@163.com"
# 密码
password = "xxxxxxx"
# smtp会话过程中的mail from地址
from_addr = "xxxxxx@163.com"
# smtp会话过程中的rcpt to地址
to_addr = "yyyyyy@163.com"
# 信件内容
msg = "my test mail"

svr = smtplib.SMTP(mailserver)
# 设置为调试模式,就是在会话过程中会有输出信息
svr.set_debuglevel(1)
# ehlo命令,docmd方法包括了获取对方服务器返回信息
svr.docmd("EHLO server")
# auth login 命令
svr.docmd("AUTH LOGIN")
# 发送用户名,是base64编码过的,用send发送的,所以要用getreply获取返回信息
svr.send(base64.encodestring(username))
svr.getreply()
# 发送密码
svr.send(base64.encodestring(password))
svr.getreply()
# mail from, 发送邮件发送者
svr.docmd("MAIL FROM: <%s>" % from_addr)
# rcpt to, 邮件接收者
svr.docmd("RCPT TO: <%s>" % to_addr)
# data命令,开始发送数据
svr.docmd("DATA")
# 发送正文数据
svr.send(msg)
# 比如以 . 作为正文发送结束的标记
svr.send(" . ")
svr.getreply()
# 发送结束,退出
svr.quit()

Copy after login


上面说的是最普通的情况,但是不能忽略的是现在好多企业邮件是支持安全邮件的,就是通过SSL发送的邮件,这个怎么发呢?SMTP对SSL安全邮件的支持有两种方案,一种老的是专门开启一个465端口来接收ssl邮件,另一种更新的做法是在标准的25端口的smtp上增加一个starttls的命令来支持。
看看第一种怎么办:

#-*- encoding: gb2312 -*-
import os, sys, string, socket
import smtplib


class SMTP_SSL (smtplib.SMTP):
  def __init__(self, host='', port=465, local_hostname=None, key=None, cert=None):
    self.cert = cert
    self.key = key
    smtplib.SMTP.__init__(self, host, port, local_hostname)
    
  def connect(self, host='localhost', port=465):
    if not port and (host.find(':') == host.rfind(':')):
      i = host.rfind(':')
      if i >= 0:
        host, port = host[:i], host[i+1:]
        try: port = int(port)
        except ValueError:
          raise socket.error, "nonnumeric port"
    if not port: port = 654
    if self.debuglevel > 0: print>>stderr, 'connect:', (host, port)
    msg = "getaddrinfo returns an empty list"
    self.sock = None
    for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
      af, socktype, proto, canonname, sa = res
      try:
        self.sock = socket.socket(af, socktype, proto)
        if self.debuglevel > 0: print>>stderr, 'connect:', (host, port)
        self.sock.connect(sa)
        # 新增加的创建ssl连接
        sslobj = socket.ssl(self.sock, self.key, self.cert)
      except socket.error, msg:
        if self.debuglevel > 0: 
          print>>stderr, 'connect fail:', (host, port)
        if self.sock:
          self.sock.close()
        self.sock = None
        continue
      break
    if not self.sock:
      raise socket.error, msg

    # 设置ssl
    self.sock = smtplib.SSLFakeSocket(self.sock, sslobj)
    self.file = smtplib.SSLFakeFile(sslobj);

    (code, msg) = self.getreply()
    if self.debuglevel > 0: print>>stderr, "connect:", msg
    return (code, msg)
    
if __name__ == '__main__':
  smtp = SMTP_SSL('192.168.2.10')
  smtp.set_debuglevel(1)
  smtp.sendmail("zzz@xxx.com", "zhaowei@zhaowei.com", "xxxxxxxxxxxxxxxxx")
  smtp.quit()

Copy after login


这里我是从原来的smtplib.SMTP派生出了新的SMTP_SSL类,它专门来处理ssl连接。我这里测试的192.168.2.10是我自己的测试服务器.
第二种是新增加了starttls的命令,这个很简单,smtplib里就有这个方法,叫smtplib.starttls()。当然,不是所有的邮件系统都支持安全邮件的,这个需要从ehlo的返回值里来确认,如果里面有starttls,才表示支持。相对于发送普通邮件的第二种方法来说,只需要新增加一行代码就可以了:

#-*- encoding: gb2312 -*-
import os, sys, string
import smtplib
import base64

# 邮件服务器地址
mailserver = "smtp.163.com"
# 邮件用户名
username = "xxxxxx@163.com"
# 密码
password = "xxxxxxx"
# smtp会话过程中的mail from地址
from_addr = "xxxxxx@163.com"
# smtp会话过程中的rcpt to地址
to_addr = "yyyyyy@163.com"
# 信件内容
msg = "my test mail"

svr = smtplib.SMTP(mailserver)
# 设置为调试模式,就是在会话过程中会有输出信息
svr.set_debuglevel(1)
# ehlo命令,docmd方法包括了获取对方服务器返回信息,如果支持安全邮件,返回值里会有starttls提示
svr.docmd("EHLO server")
svr.starttls() # <------ 这行就是新加的支持安全邮件的代码!
# auth login 命令
svr.docmd("AUTH LOGIN")
# 发送用户名,是base64编码过的,用send发送的,所以要用getreply获取返回信息
svr.send(base64.encodestring(username))
svr.getreply()
# 发送密码
svr.send(base64.encodestring(password))
svr.getreply()
# mail from, 发送邮件发送者
svr.docmd("MAIL FROM: <%s>" % from_addr)
# rcpt to, 邮件接收者
svr.docmd("RCPT TO: <%s>" % to_addr)
# data命令,开始发送数据
svr.docmd("DATA")
# 发送正文数据
svr.send(msg)
# 比如以 . 作为正文发送结束的标记
svr.send(" . ")
svr.getreply()
# 发送结束,退出
svr.quit()

Copy after login

注意: 以上的代码为了方便我都没有判断返回值,严格说来,是应该判断一下返回的代码的,在smtp协议中,只有返回代码是2xx或者3xx才能继续下一步,返回4xx或5xx的,都是出错了。

Related labels:
source:php.cn
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template
About us Disclaimer Sitemap
php.cn:Public welfare online PHP training,Help PHP learners grow quickly!