本篇主要实现了一个手动发送电子邮件的“代码客户端”。

示例1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import smtplib, sys

message_template = """To: {}
From: {}
Subject: Test Message from test.py
Hello,
This is a test message send to you from the test.py program in Foundations of python Network Programming.
"""

def main():
   if len(sys.argv) < 4:
       name = sys.argv[0]
       print("Usage: {} server fromaddr toaddr [toaddr...]".format(name))
       sys.exit(2)
   server, fromaddr, toaddr = sys.argv[1], sys.argv[2], sys.argv[3:]
   message = message_template.format((",".join(toaddr)), fromaddr)
   connection = smtplib.SMTP(server)
   connection.sendmail(fromaddr, toaddr, message)
   connection.quit()
   
   s = "" if len(toaddr) == 1 else "s"
   print("Message send to {} recopint{}".format(len(toaddr), s))


if __name__ == '__main__':
   main()

在命令行运行上面的文件,应该能够连接成功并发送:

1
2
$ python3 test.py mail.example.com sender@example.com recipient@example.com
Message send to 1 recipient

本示例完全使用的是python内置函数,无第三方包。

  当然,有时候使用上面代码运行时会报错。很大可能原因是由于很多大公司的电子邮件服务器需要我们提供账号密码进行登录验证来证明我们并非垃圾邮件发送者。这就涉及到了连接SMTP服务器需要认证,否则就不允许我们发送电子邮件。

  对于认证本身是相当简单的。smtplib提供了一个login()函数,该函数以用户名和密码作为参数进行合法的SMTP验证,这样就保证了合法的身份,如示例二。

示例二

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import smtplib, sys
from getpass import getpass

message_template = """To: {}
From: {}
Subject: Test Message from test.py
Hello,
This is a test message send to you from the test.py program in Foundations of python Network Programming.
"""

def main():
   if len(sys.argv) < 4:
       name = sys.argv[0]
       print("Usage: {} server fromaddr toaddr [toaddr...]".format(name))
       sys.exit(2)
   server, fromaddr, toaddr = sys.argv[1], sys.argv[2], sys.argv[3:]
   message = message_template.format((",".join(toaddr)), fromaddr)

   username = input("Enter username: ")
   password = getpass("Enter password: ")

   connection = smtplib.SMTP(server)
   connection.login(username, password)

   connection.sendmail(fromaddr, toaddr, message)

   s = "" if len(toaddr) == 1 else "s"
   print("Message send to {} recopint{}".format(len(toaddr), s))
   connection.quit()


if __name__ == '__main__':
   main()

  示例二所示,SMTP的用户验证问题得以解决,但是在运行方面难免会有各种各样的问题发生,代码不够健壮性。为了增强代码的健壮性,以及各方面的“突发”问题,对代码进行了重构,形成示例三的最终代码。

示例三

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import smtplib, socket, sys
from getpass import getpass

message_template = """To: {}
From: {}
Subject: Test Message from test.py
Hello,
This is a test message send to you from the test.py program in Foundations of python Network Programming.
"""

def main():
   if len(sys.argv) < 4:
       name = sys.argv[0]
       print("Usage: {} server fromaddr toaddr [toaddr...]".format(name))
       sys.exit(2)
   server, fromaddr, toaddr = sys.argv[1], sys.argv[2], sys.argv[3:]
   message = message_template.format((",".join(toaddr)), fromaddr)

   username = input("Enter username: ")
   password = getpass("Enter password: ")

   try:
       connection = smtplib.SMTP(server)
       try:
           connection.login(username, password)
       except smtplib.SMTPException as e:
           print("Authentication failed:", e)
           sys.exit(1)
       connection.sendmail(fromaddr, toaddr, message)
   except (socket.gaierror, socket.error, socket.herror, smtplib.SMTPException) as e:
       print("Your message may not have been sent!")
       print(e)
       sys.exit(1)
   else:
       s = "" if len(toaddr) == 1 else "s"
       print("Message send to {} recopint{}".format(len(toaddr), s))
       connection.quit()


if __name__ == '__main__':
   main()

  这里需要说明一点的是,在验证SMTP时,如:新浪邮箱等,需要输入账号密码进行验证。而有的则不用输入密码,如:QQ邮箱,密码只需要输入授权码即可。具体操作可根据异常信息自行判断。