Come inviare una mail con Python?



Answers

Bene, vuoi avere una risposta aggiornata e moderna.

Ecco la mia risposta:

Quando ho bisogno di spedire mail in python, io uso l'API mailgun che ottiene un sacco di grattacapi con l'invio di mail risolte. Hanno un'app / API meravigliosa che ti consente di inviare 10.000 email al mese gratuitamente.

L'invio di un'email sarebbe come questo:

def send_simple_message():
    return requests.post(
        "https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages",
        auth=("api", "YOUR_API_KEY"),
        data={"from": "Excited User <mailgun@YOUR_DOMAIN_NAME>",
              "to": ["bar@example.com", "YOU@YOUR_DOMAIN_NAME"],
              "subject": "Hello",
              "text": "Testing some Mailgun awesomness!"})

Puoi anche tenere traccia degli eventi e molto altro, vedere la guida rapida .

Spero che tu trovi questo utile!

Question

Questo codice funziona e mi invia una e-mail bene:

import smtplib
#SERVER = "localhost"

FROM = 'monty@python.com'

TO = ["jon@mycompany.com"] # must be a list

SUBJECT = "Hello!"

TEXT = "This message was sent with Python's smtplib."

# Prepare actual message

message = """\
From: %s
To: %s
Subject: %s

%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)

# Send the mail

server = smtplib.SMTP('myserver')
server.sendmail(FROM, TO, message)
server.quit()

Tuttavia se provo a racchiuderlo in una funzione come questa:

def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
    import smtplib
    """this is some test documentation in the function"""
    message = """\
        From: %s
        To: %s
        Subject: %s
        %s
        """ % (FROM, ", ".join(TO), SUBJECT, TEXT)
    # Send the mail
    server = smtplib.SMTP(SERVER)
    server.sendmail(FROM, TO, message)
    server.quit()

e chiamalo ottengo i seguenti errori:

 Traceback (most recent call last):
  File "C:/Python31/mailtest1.py", line 8, in <module>
    sendmail.sendMail(sender,recipients,subject,body,server)
  File "C:/Python31\sendmail.py", line 13, in sendMail
    server.sendmail(FROM, TO, message)
  File "C:\Python31\lib\smtplib.py", line 720, in sendmail
    self.rset()
  File "C:\Python31\lib\smtplib.py", line 444, in rset
    return self.docmd("rset")
  File "C:\Python31\lib\smtplib.py", line 368, in docmd
    return self.getreply()
  File "C:\Python31\lib\smtplib.py", line 345, in getreply
    raise SMTPServerDisconnected("Connection unexpectedly closed")
smtplib.SMTPServerDisconnected: Connection unexpectedly closed

Qualcuno può aiutarmi a capire perché?




C'è un problema di indentazione. Il codice seguente funzionerà:

import textwrap

def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
    import smtplib
    """this is some test documentation in the function"""
    message = textwrap.dedent("""\
        From: %s
        To: %s
        Subject: %s
        %s
        """ % (FROM, ", ".join(TO), SUBJECT, TEXT))
    # Send the mail
    server = smtplib.SMTP(SERVER)
    server.sendmail(FROM, TO, message)
    server.quit()



Mentre indentate il vostro codice nella funzione (che è ok), avete anche fatto rientrare le righe della stringa di messaggio non elaborata. Ma lo spazio bianco principale implica la piegatura (concatenazione) delle linee di intestazione, come descritto nelle sezioni 2.2.3 e 3.2.3 di RFC 2822 - Formato messaggio Internet :

Ogni campo di intestazione è logicamente una singola riga di caratteri che comprende il nome del campo, i due punti e il corpo del campo. Per comodità, tuttavia, e per gestire le limitazioni di 998/78 caratteri per riga, la porzione di campo di un campo di intestazione può essere suddivisa in una rappresentazione a più righe; questo è chiamato "pieghevole".

Nella forma di funzione della tua chiamata sendmail , tutte le linee iniziano con uno spazio bianco e quindi sono "unfolded" (concatenate) e stai provando ad inviare

From: monty@python.com    To: jon@mycompany.com    Subject: Hello!    This message was sent with Python's smtplib.

A parte la nostra ipotesi, smtplib non capirà più le intestazioni To: and Subject: perché questi nomi vengono riconosciuti solo all'inizio di una riga. Invece smtplib assumerà un indirizzo email del mittente molto lungo:

monty@python.com    To: jon@mycompany.com    Subject: Hello!    This message was sent with Python's smtplib.

Questo non funzionerà e così viene la tua eccezione.

La soluzione è semplice: basta conservare la stringa del message come era prima. Questo può essere fatto con una funzione (come suggerito da Zeeshan) o immediatamente nel codice sorgente:

import smtplib

def sendMail(FROM,TO,SUBJECT,TEXT,SERVER):
    """this is some test documentation in the function"""
    message = """\
From: %s
To: %s
Subject: %s

%s
""" % (FROM, ", ".join(TO), SUBJECT, TEXT)
    # Send the mail
    server = smtplib.SMTP(SERVER)
    server.sendmail(FROM, TO, message)
    server.quit()

Ora lo spiegamento non si verifica e tu mandi

From: monty@python.com
To: jon@mycompany.com
Subject: Hello!

This message was sent with Python's smtplib.

che è ciò che funziona e cosa è stato fatto con il tuo vecchio codice.

Nota che stavo anche conservando la linea vuota tra intestazioni e corpo per adattare la sezione 3.5 della RFC (che è richiesta) e metti l'inclusione al di fuori della funzione secondo la guida in stile Python PEP-0008 (che è opzionale).




Ecco un esempio su Python 3.x , molto più semplice di 2.x :

import smtplib
from email.message import EmailMessage
def send_mail(to_email, subject, message, server='smtp.example.cn',
              from_email='xx@example.com'):
    # import smtplib
    msg = EmailMessage()
    msg['Subject'] = subject
    msg['From'] = from_email
    msg['To'] = ', '.join(to_email)
    msg.set_content(message)
    print(msg)
    server = smtplib.SMTP(server)
    server.set_debuglevel(1)
    server.login(from_email, 'password')  # user & password
    server.send_message(msg)
    server.quit()
    print('successfully sent the mail.')

chiama questa funzione:

send_mail(to_email=['12345@qq.com', '12345@126.com'],
          subject='hello', message='Your analysis has done!')

sotto può solo per utente cinese:

Se usi 126/163, 网易 邮箱, devi impostare "客户 端 授权 密码", come di seguito:

ref: https://.com/a/41470149/2803344 https://docs.python.org/3/library/email.examples.html#email-examples




Per quanto riguarda il tuo codice, sembra che non ci sia nulla di fondamentalmente sbagliato in questo, tranne che, non è chiaro come stai effettivamente chiamando quella funzione. Tutto quello che posso pensare è che quando il tuo server non risponde, otterrai questo errore SMTPServerDisconnected. Se cerchi la funzione getreply () in smtplib (estratto sotto), ti verrà un'idea.

def getreply(self):
    """Get a reply from the server.

    Returns a tuple consisting of:

      - server response code (e.g. '250', or such, if all goes well)
        Note: returns -1 if it can't read response code.

      - server response string corresponding to response code (multiline
        responses are converted to a single, multiline string).

    Raises SMTPServerDisconnected if end-of-file is reached.
    """

controlla un esempio su https://github.com/rreddy80/sendEmails/blob/master/sendEmailAttachments.py che utilizza anche una chiamata di funzione per inviare un'email, se è quello che stai cercando di fare (approccio DRY).




Related