python smtplib email

监控系统需要触发报警邮件, 简单笔记一下的用到的库.

smtplib

classsmtplib.SMTP([host[, port[, local_hostname[, timeout]]]])

返回一个 smtp 实例, 如果指定了 host 和 port, 会调用 SMTP.connect() 进行连接, timout 指定超时时间

classsmtplib.SMTP_SSL([host[, port[, local_hostname[, keyfile[, certfile[, timeout]]]]]])

返回一个 ssl 模式的 smtp 实例, 仅在 SMTP.starttls() 无法或不推荐时使用

SMTP.set_debuglevel(level)

设置 debug 输出级别. 如果 level 设定为真值, 则会输出所有的调试信息和整个连接过程中收到和发送的信息.

SMTP.connect([host[, port]])

连接到指定 host 的端口. 默认 host 为 localhost, 默认端口为25

SMTP.helo([hostname])

跟 SMTP 邮件服务器介绍下自己, 一般情况下不需要直接执行此命令, 直接调用 SMTP.sendmail()

SMTP.ehlo([hostname])

跟 ESMTP 邮件服务器 say hello

SMTP.verify(address)

确认邮件地址的有效性, 如果有效会返回 code 250 和完成的有点地址, 大部分邮件服务器会屏蔽此命令以防垃圾邮件

SMTP.login(user, password)

登录到邮件服务器

SMTP.starttls([keyfile[, certfile]])

将 smtp 连接切换到 tls 模式

SMTP.sendmail(from_addr, to_addrs, msg[, mail_options, rcpt_options])

发邮件

from_addr string 发件人

to_addrs list 收件人

msg string 信息

SMTP.quit()

终止 smtp 会话, 关闭链接.

SMTP Example

import smtplib

def prompt(prompt):
    return raw_input(prompt).strip()

fromaddr = prompt("From: ")
toaddrs  = prompt("To: ").split()
print "Enter message, end with ^D (Unix) or ^Z (Windows):"

# Add the From: and To: headers at the start!
msg = ("From: %s\r\nTo: %s\r\n\r\n"
       % (fromaddr, ", ".join(toaddrs)))
while 1:
    try:
        line = raw_input()
    except EOFError:
        break
    if not line:
        break
    msg = msg + line

print "Message length is " + repr(len(msg))

server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

注意到 msg 需要添加一个邮件头, 格式是

"""

From: test@gmail.com

To: test@gmail.com, test1@gmail.com, test2@gmail.com



邮件正文

"""

显然这样攒 msg 不是一个好办法, 所以 python 提供了 email

邮件发送 html

#!/usr/bin/env python

import smtplib

from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# me == my email address
# you == recipient's email address
me = "my@email.com"
you = "your@email.com"

# Create message container - the correct MIME type is multipart/alternative.
msg = MIMEMultipart('alternative')
msg['Subject'] = "Link"
msg['From'] = me
msg['To'] = you

# Create the body of the message (a plain-text and an HTML version).
text = "Hi!\nHow are you?\nHere is the link you wanted:\nhttps://www.python.org"
html = """\
<html>
  <head></head>
  <body>
    <p>Hi!<br>
       How are you?<br>
       Here is the <a href="https://www.python.org">link</a> you wanted.
    </p>
  </body>
</html>
"""

# Record the MIME types of both parts - text/plain and text/html.
part1 = MIMEText(text, 'plain')
part2 = MIMEText(html, 'html')

# Attach parts into message container.
# According to RFC 2046, the last part of a multipart message, in this case
# the HTML message, is best and preferred.
msg.attach(part1)
msg.attach(part2)

# Send the message via local SMTP server.
s = smtplib.SMTP('localhost')
# sendmail function takes 3 arguments: sender's address, recipient's address
# and message to send - here it is sent as one string.
s.sendmail(me, you, msg.as_string())
s.quit()

1. 注意到 MIMEMultipart 和 MIMEText, 从返回对象的关系看, MIMEText 的对象可以被 attach 到 MIMEMultipart 返回的对象上

2. 如果实际测试这段代码, 会发现虽然 attach 两次, 但是收到的只有一个 html 的内容, 这跟 MIMEMultipart("alternative") 有关

3. 如果初始化时选择 MIMEMultipart("mixed"), 会发现邮件内容是 text 文本, 同时携带一个 .html 的附件

4. 如果只选择 attach(part2), 发现邮件内容是 html

5. MIMEMultipart 的实例, 包含邮件标题 Subject, 发件人 From, 收件人 To, 最后 attach MIMEText 的实例

6. 这里注意, 如果有多个收件人, To 应该是以 ; 间隔的字符串, 虽然使用 , 间隔也可以成功, 但是 ; 是标准的写法

7. 这跟 sendmail 中的收件人是不同的, sendmail 中的收件人是 list 列表, 如果把 To 作为参数传给 sendmail, 那么只会有第一个人收到邮件

classemail.mime.multipart.MIMEMultipart([_subtype[, boundary[, _subparts[, _params]]]])

_subtype

multipart/mixed

A number of different resources are combined in a single message.

multipart/alternative

The section 5.1.4 of RFC 2046 defines multipart/alternative MIME type to allow the sender to provide different, interchangeable representations of the same message and to leave it up to the receiver to chose the form of presentation most suitable for its capabilities

classemail.mime.text.MIMEText(_text[, _subtype[, _charset]])

如果发送中文, 需要指定 _charset="utf8"