python实现本地邮件发送

2010-05-20 21:48

之前一直忍受Thunderbird的荼毒, 换上KMail后一身轻, 感觉很开心. 于是有了将本地报警和通知转成邮件的冲动. 作为第一步, 就是要用KMail收取本地的邮件. 今天就整了整这个.

要用KMail收取本地邮件, 你需要一个本地邮件服务器(更具体的说是MTA). 这个我用的是exim, 因为Slackware默认的sendmail比我的岁数都大, 而且实际使用中也发现有些小问题. exim的安装和配置比较容易, 我基本上就只是改了默认端口而已.

接下来是要写一个程序能够发送本地邮件. 这个功能是smtplib这个库实现的. 基本的框架是这样的(继续无耻抄袭python官方文档):

import sys
import smtplib

msg = sys.argv[1]
fromaddr = "<xiaket@bolt>"
toaddrs = "<xiaket@bolt>"
server = smtplib.SMTP('localhost')
server.set_debuglevel(1)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

这段代码里的bolt是我的主机名.

一切正常的话, 执行这个脚本应该能够给自己的用户发一封邮件, 你可以从debug信息里面看到发送过程中你的python脚本和服务器的通讯. 邮件发送完成后, 你可以在本地邮箱(例如: /var/mail/xiaket)里找到它的内容. KMail的配置也很简单, 给出到本地邮箱的路径即可.

接下来要做的事情就是完善我们的python脚本了. 我们要实现的目标是, 既能够当作本地命令执行又能够作为python模块被导入. 于是大概的框架应该是这样的:

import smtplib
import sys


def send(message):
fromaddr = "<xiaket@bolt>"
toaddrs = "<xiaket@bolt>"

# I used a bizzare port to receive mail.
server = smtplib.SMTP('localhost', '9025')
server.sendmail(fromaddr, toaddrs, message)
server.quit()


if __name__ == "__main__":
if len(sys.argv) != 2:
print "Usage: mailer message"
exit(1)
send(sys.argv[1])

不过现在还有一个问题是这样发出来的邮件没有标题, 编码和From/To信息. 找了找文档, 发现应该用email这个库, 用类似字典键值的方式给MIMEText这个类的实例添加属性, 最后用一个as_string转成字符串传给sendmail即可.

from email.mime.text import MIMEText

mail = MIMEText(content, 'plain', 'utf-8')
mail['Subject'] = subject
mail['From'] = "%s <xiaket@localhost>" % category
mail['To'] = 'me <xiaket@localhost>'
server.sendmail(fromaddr, toaddrs, mail.as_string())

这样, 代码基本就完成了, 把这段代码命名为mailer.py, 放到我自己定义的PYTHONPATH里, 然后做一个软链接放到PATH下, 测试完成以后就大功告成了~ 使用起来还是挺方便的, 在命令行下:

mailer 测试类别 测试主题 测试内容

在python里面调用函数:

>>> from mailer import send
>>> send(category="测试类别", subject="测试主题", content="测试内容")