lavr / python-emails

Modern python library for emails
http://python-emails.readthedocs.org
Other
400 stars 54 forks source link

Reuse connection #154

Closed fph closed 4 years ago

fph commented 4 years ago

It seems that the library opens a new SMTP connection whenever it sends a new message.

This caused me some problems because when sending more than 3-4 messages in a row my SMTP server starts refusing connections ("too many connections from your_ip").

It would be nice to have a clean way to reuse the same SMTP connection to send multiple messages at the same time.

lavr commented 4 years ago

Hi! Default emails.backend.SMTPBackend does not close smtp connection specially to reuse it. Can you show part of code that causes problem ?

fph commented 4 years ago

Thanks for your help!

Here is my code, with syntax taken from https://python-emails.readthedocs.io/en/latest/ . This snippet reads filenames and target addresses from a dictionary like testers = {'example.pdf': 'example@example.com', 'otherfile': 'other@example.com'}, and sends each file to each address.

    for filename, address in testers.items():
        message = emails.Message(text='Redacted',
            subject='Redacted',
            mail_from=('Redacted', 'redacted@example.com'),
            headers={"Reply-To": "redacted@example.com"}
            )
        message.attach(filename=filename, data=open(filename, 'rb'))
        response = message.send(
            to = address,
            smtp = {'host': 'redacted.example.com', 'port': 587, 'tls': True, 'user': 'redacted', 'password':  secret}
            )
        # some error checking on response follows. Apparently response.statuscode is None when the connection fails.
lavr commented 4 years ago

Try creating SMTPBackend object like this:

from emails.backend import SMTPBackend

backend = SMTPBackend(**{'host': 'redacted.example.com', 'port': 587, 'tls': True, 'user': 'redacted', 'password':  secret})

for filename, address in testers.items():
    message = emails.Message(...)
    message.attach(...)
    response = message.send(to = address, smtp = backend)

backend.close() # optional 
fph commented 4 years ago

Thanks; I confirm that this works for me. I suggest adding an example using SMTPBackend to the documentation; it seems a common use case!

fph commented 4 years ago

Reopening because after further testing it seems that this syntax does not reuse the same connection, in fact. I still get errors (with an unhelpful (response.status_code, response.status_text) = (None, None)) after sending the first 5 e-mails, which presumably means that the server refuses my connections.

fph commented 4 years ago

Oof, sorry, ignore the previous message; found the problem in my code.