Могу ли я отправлять разные письма разным получателям с разными сообщениями? - PullRequest
1 голос
/ 15 июня 2019

Я пытаюсь отправить электронную почту с разными сообщениями разным получателям через 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 голосов
/ 18 июня 2019

То, как вы определили Mail, msg, является атрибутом класса, поэтому каждый экземпляр 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 заголовки From и To представляют собой списки с несколькими значениями:

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

Одним из решений вашей проблемы может быть удаление заголовков From и To перед назначением нового значения в цикле.

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 to_addrs параметр принимает список, поэтому 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 экземпляр со всеми вещами , которые не меняются; и один экземпляр EmailServer затем использует цикл для добавления нескольких адресов к экземпляру Mail. Затем отправьте письмо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...