原文:Send Emails Using Python,作者:Arjun Krishna Babu

作为一项学习练习,我最近深入研究了 Python 3,以了解如何发送大量电子邮件。在生产环境中可能有更直接的方法可以做到这一点,但以下方法对我来说效果很好。

这是一个场景:你有一堆联系人的姓名和电子邮件地址,并且你想向这些联系人中的每一个发送消息,同时在消息顶部添加 “Dear [name]”。

为简单起见,你可以将联系人详细信息存储在文件中而不是数据库中,你还可以将要发送的消息模板存储在文件中。

Python 的 smtplib 模块基本上是你发送简单电子邮件所需的全部,无需任何主题行或此类附加信息。但对于真正的电子邮件,你确实需要一个主题行和大量信息——甚至可能是图片和附件。

这就是 Python 的电子邮件包的用武之地。请记住,仅使用电子邮件包是不可能发送邮件的,你需要电子邮件和 smtplib 的组合。

请务必查看这两个方面的全面的官方文档。

以下是使用 Python 发送电子邮件的四个基本步骤:

  • 设置 SMTP 服务器并登录你的帐户。
  • 创建 MIMEMultipart 消息对象,并使用 FromToSubject 字段的适当标头加载它
  • 添加你的消息正文
  • 使用 SMTP 服务器对象发送消息

现在让我带你完成整个过程。

假设你有一个联系人文件 mycontacts.txt,如下所示:

user@computer ~ $ cat mycontacts.txt
john johndoe@example.com
katie katie2016@example.com

每条线代表一个联系人。我们有名称后跟电子邮件地址。我将所有内容都以小写形式存储。如有必要,我将把它留给编程逻辑来将任何字段转换为大写或句子大小写。所有这些在 Python 中都非常简单。

然后,我们有消息模板文件 message.txt

user@computer ~ $ cat message.txt 

Dear ${PERSON_NAME}, 

This is a test message. 
Have a great weekend! 

Yours Truly

注意到 “${PERSON_NAME}” 这个词了吗?那是 Python 中的模板字符串。模板字符串可以很容易地被替换为其他字符串;在此示例中,${PERSON_NAME} 将被替换为该人的实际姓名,你很快就会看到。

现在让我们从 Python 代码开始。首先,我们需要从 mycontacts.txt 文件中读取联系人。我们不妨把它放到一个函数中。

# Function to read the contacts from a given contact file and return a
# list of names and email addresses
def get_contacts(filename):
    names = []
    emails = []
    with open(filename, mode='r', encoding='utf-8') as contacts_file:
        for a_contact in contacts_file:
            names.append(a_contact.split()[0])
            emails.append(a_contact.split()[1])
    return names, emails

函数 get_contacts() 将文件名作为其参数。它将打开文件,读取每一行(即每个联系人),将其拆分为姓名和电子邮件,然后将它们附加到两个单独的列表中。最后,从函数返回两个列表。

我们还需要一个函数来读取模板文件(如 message.txt),并返回由其内容制成的 Template 对象。

from string import Template

def read_template(filename):
    with open(filename, 'r', encoding='utf-8') as template_file:
        template_file_content = template_file.read()
    return Template(template_file_content)

就像前面的函数一样,这个函数将文件名作为参数。

要发送电子邮件,你需要使用 SMTP(简单邮件传输协议)。如前所述,Python 提供了库来处理此任务。

# import the smtplib module. It should be included in Python by default
import smtplib
# set up the SMTP server
s = smtplib.SMTP(host='your_host_address_here', port=your_port_here)
s.starttls()
s.login(MY_ADDRESS, PASSWORD)

在上面的代码片段中,你将导入 smtplib,然后创建一个封装 SMTP 连接的 SMTP 实例。它将主机地址和端口号作为参数,这两者都完全取决于特定电子邮件服务提供商的 SMPT 设置。例如,在 Outlook 的情况下,上面的第 4 行将改为:

s = smtplib.SMTP(host='smtp-mail.outlook.com', port=587)

你应该使用你的特定电子邮件服务提供商的主机地址和端口号来使整个程序正常进行。

上面的 MY_ADDRESSPASSWORD 是两个变量,用于保存你要使用的帐户的完整电子邮件地址和密码。

现在是使用我们上面定义的函数获取联系信息和消息模板的好时机。

names, emails = get_contacts('mycontacts.txt')  # read contacts
message_template = read_template('message.txt')

现在,对于每个联系人,让我们分别发送邮件。

# import necessary packages
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

# For each contact, send the email:
for name, email in zip(names, emails):
    msg = MIMEMultipart()       # create a message

    # add in the actual person name to the message template
    message = message_template.substitute(PERSON_NAME=name.title())

    # setup the parameters of the message
    msg['From']=MY_ADDRESS
    msg['To']=email
    msg['Subject']="This is TEST"

    # add in the message body
    msg.attach(MIMEText(message, 'plain'))

    # send the message via the server set up earlier.
    s.send_message(msg)
    
    del msg

对于每个 nameemail(来自联系人文件),你将创建一个 MIMEMultipart 对象,将 FromToSubject 内容类型标头设置为关键字字典,然后将消息正文作为纯文本附加到 MIMEMultipart 对象。你可能需要阅读文档以了解有关你可以试验的其他 MIME 类型的更多信息。

另请注意,在上面的第 10 行,我使用 Python 中的模板机制${PERSON_NAME} 替换为从联系人文件中提取的实际名称。

在这个特定的示例中,我将删除 MIMEMultipart 对象,并在每次迭代循环时重新创建它。

完成后,你可以使用之前创建的 SMTP 对象的方便的 send_message() 函数发送消息。

这是完整的代码:

import smtplib

from string import Template

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

MY_ADDRESS = 'my_address@example.comm'
PASSWORD = 'mypassword'

def get_contacts(filename):
    """
    Return two lists names, emails containing names and email addresses
    read from a file specified by filename.
    """
    
    names = []
    emails = []
    with open(filename, mode='r', encoding='utf-8') as contacts_file:
        for a_contact in contacts_file:
            names.append(a_contact.split()[0])
            emails.append(a_contact.split()[1])
    return names, emails

def read_template(filename):
    """
    Returns a Template object comprising the contents of the 
    file specified by filename.
    """
    
    with open(filename, 'r', encoding='utf-8') as template_file:
        template_file_content = template_file.read()
    return Template(template_file_content)

def main():
    names, emails = get_contacts('mycontacts.txt') # read contacts
    message_template = read_template('message.txt')

    # set up the SMTP server
    s = smtplib.SMTP(host='your_host_address_here', port=your_port_here)
    s.starttls()
    s.login(MY_ADDRESS, PASSWORD)

    # For each contact, send the email:
    for name, email in zip(names, emails):
        msg = MIMEMultipart()       # create a message

        # add in the actual person name to the message template
        message = message_template.substitute(PERSON_NAME=name.title())

        # Prints out the message body for our sake
        print(message)

        # setup the parameters of the message
        msg['From']=MY_ADDRESS
        msg['To']=email
        msg['Subject']="This is TEST"
        
        # add in the message body
        msg.attach(MIMEText(message, 'plain'))
        
        # send the message via the server set up earlier.
        s.send_message(msg)
        del msg
        
    # Terminate the SMTP session and close the connection
    s.quit()
    
if __name__ == '__main__':
    main()

就是这些啦,我相信代码现在相当清晰。

如有必要,请随意复制和调整它。

除了官方的 Python 文档,我还想提一下这个对我有很大帮助的资源

快乐编码:)

我最初在这里发表了这篇文章。如果你喜欢这篇文章,请和朋友们分享它,谢谢!