我可以通过不同的消息向不同的收件人发送不同的邮件吗?

时间:2019-06-15 13:01:08

标签: python smtp

我正在尝试通过libsmtp和gmail将具有不同消息的电子邮件发送到不同的收件人。

我尝试在不关闭smtp连接的情况下发送邮件。它只是将所有消息发送到同一接收者,但我想与接收者发送消息。 我尝试为每个循环打开和退出连接,但是在执行第一次迭代并退出连接后,第二次迭代会给出错误消息“ smtplib.SMTPServerDisconnected:请先运行connect()”,即使它应该再次连接。

class Mail:
    msg = MIMEMultipart()
    def __init__(self, addr_from, addr_to):
        self.msg['From'] = addr_from
        self.msg['To'] = addr_to
    def set_subject(self, subject):
        self.msg['Subject'] = subject
    def set_message(self, message):
        self.msg.attach(MIMEText(message, 'plain'))
    def attach_image(self, image_location, image_name):
        fp = open(image_location, 'rb')
        img = MIMEImage(fp.read())
        img.add_header('Content-Disposition', "attachment; filename= %s" % image_name)
        fp.close()
        self.msg.attach(img)
    def get_mail(self):
        return self.msg



class EmailServer:
    server = smtplib.SMTP('smtp.gmail.com', 587)
    def __init__(self, sender_mail, password):
        self.sender_mail = sender_mail
        self.password = password
        self.server.ehlo()
        self.server.starttls()
        self.server.login(sender_mail, password)

    def send_mail(self, mail):
        self.server.sendmail(mail['From'], mail['To'], mail.as_string())

    def quit_server(self):
        self.server.quit()

for row in range(0,x):

    name = sheet.cell_value(row, 0)
    mail_adress = sheet.cell_value(row, 1)

    print(name, mail_adress)

    mail = Mail('xxxxxxxx@gmail.com', mail_adress)
    mail.set_subject("subject")
    mail.set_message('message')
    server = EmailServer('xxxxxxxx@gmail.com', 'xxxxxxxxx')
    mail.attach_image('/Users/xxxx/xxxx/xxxx.jpg', 'title')
    server.send_mail(mail.get_mail())
    server.quit_server()

1 个答案:

答案 0 :(得分:0)

您定义Mailmsg的方式是一个类属性,因此Mail 的每个实例都包含相同的msg

import email
from email.mime.multipart import MIMEMultipart

class Mail:
    msg = MIMEMultipart()
    def __init__(self, addr_from, addr_to):
        self.msg['From'] = addr_from
        self.msg['To'] = addr_to

for afrom, ato in zip(list('abcd'),list('wert')):
    mail = Mail(afrom, ato)
    print(id(mail.msg))

In [60]: 
160675264
160675264
160675264
160675264

MIMEMultipart是email.message对象;其__setitem__文档字符串状态:...does not overwrite an existing header with the same field name. Use __delitem__() first to delete any existing headers. ...

In [61]: help(mail.msg.__setitem__)
Help on method __setitem__ in module email.message:

__setitem__(name, val) method of email.mime.multipart.MIMEMultipart instance
    Set the value of a header.

    Note: this does not overwrite an existing header with the same field
    name.  Use __delitem__() first to delete any existing headers.

在for循环之后,FromTo标头是具有多个值的列表:

mail.msg.get_all('From'), mail.msg.get_all('To')
Out[62]: (['a', 'b', 'c', 'd'], ['w', 'e', 'r', 't'])

您的问题的一种解决方案是在循环中分配新值之前删除FromTo标头。

In [63]: del mail.msg['From']

In [64]: del mail.msg['To']

In [65]: mail.msg.get_all('From'), mail.msg.get_all('To')
Out[65]: (None, None)

In [66]: mail.msg['From'] = 'z'

In [67]: mail.msg['To'] = 'y'

In [68]: mail.msg.get_all('From'), mail.msg.get_all('To')
Out[68]: (['z'], ['y'])

另一种选择可能是为每个msg实例创建一个新的Mail

class Mail:
    def __init__(self, addr_from, addr_to):
        self.msg = MIMEMultipart()
        self.msg['From'] = addr_from
        self.msg['To'] = addr_to

另一种选择是在循环之后发送邮件。 SMTP.sendmail的{​​{3}}接受列表,因此需要修改EmailServer.sendmail

class EmailServer:
    ...
    ...

    def send_mail(self, mail):
        self.server.sendmail(mail['From'], mail.get_all('To'), mail.as_string())

然后在添加多个'To'地址的循环之后

server.send_mail(mail.get_mail())
server.quit_server()

我无法对此进行测试,但应该可以。您可能应该只创建一个Mail实例,并且所有 stuff 都不会改变;然后,一个EmailServer实例使用循环将多个地址添加到Mail实例。然后发送邮件。