Come inviare un'e-mail con Gmail come provider utilizzando Python?


289

Sto cercando di inviare e-mail (Gmail) utilizzando Python, ma sto ricevendo il seguente errore.

Traceback (most recent call last):  
File "emailSend.py", line 14, in <module>  
server.login(username,password)  
File "/usr/lib/python2.5/smtplib.py", line 554, in login  
raise SMTPException("SMTP AUTH extension not supported by server.")  
smtplib.SMTPException: SMTP AUTH extension not supported by server.

Lo script Python è il seguente.

import smtplib
fromaddr = 'user_me@gmail.com'
toaddrs  = 'user_you@gmail.com'
msg = 'Why,Oh why!'
username = 'user_me@gmail.com'
password = 'pwd'
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(username,password)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()

16
Questa domanda dovrebbe essere sbloccata ora che Google si sta spostando verso un'API interna per l'invio di messaggi tramite Gmail. Questa mossa rende obsolete tutte le risposte tranne una, e l'unica risposta pertinente è molto leggera nel risolvere effettivamente il problema.
Andrew,

Inoltre, per gli utenti VPN, se il problema persiste, disattivare la VPN. Questo ha funzionato per me.
Paul

Risposte:


211

Devi dire EHLO prima di imbatterti in STARTTLS:

server = smtplib.SMTP('smtp.gmail.com:587')
server.ehlo()
server.starttls()

Inoltre si dovrebbe davvero creare From:, To:e Subject:le intestazioni dei messaggi, separata dal corpo del messaggio da una riga vuota e l'uso CRLFcome marcatori EOL.

Per esempio

msg = "\r\n".join([
  "From: user_me@gmail.com",
  "To: user_you@gmail.com",
  "Subject: Just a message",
  "",
  "Why, oh why"
  ])

2
invocando server.sendmail (fromaddr, toaddrs, msg) il secondo parametro, toaddrs deve essere un elenco, toaddrs = ['user_me@gmail.com']
Massimo Fazzolari

14
A partire da agosto 2014 questo genera ora smtplib.SMTPAuthenticationError: (534, '5.7.9 Richiesto password specifica per l'applicazione.
anon58192932

7
Per quanto mi riguarda, ho dovuto abilitare una password 'app' per accedere utilizzando un account @google per inviare e-mail tramite Python: support.google.com/accounts/answer/…
anon58192932

1
Ecco un link su come posta più persone: stackoverflow.com/questions/8856117/...
anon58192932

1
Una volta ho effettuato l'accesso a un server SMTP tramite telnet e inviato EHLOper errore di battitura. Dopo aver provato HELO molte volte, ma la risposta è stata diversa. Ci sono volute ore per capire che EHLO è in realtà un comando comprensibile a SMTP e ho fatto l'errore di battitura.
Shiplu Mokaddim,

297
def send_email(user, pwd, recipient, subject, body):
    import smtplib

    FROM = user
    TO = recipient if isinstance(recipient, list) else [recipient]
    SUBJECT = subject
    TEXT = body

    # Prepare actual message
    message = """From: %s\nTo: %s\nSubject: %s\n\n%s
    """ % (FROM, ", ".join(TO), SUBJECT, TEXT)
    try:
        server = smtplib.SMTP("smtp.gmail.com", 587)
        server.ehlo()
        server.starttls()
        server.login(user, pwd)
        server.sendmail(FROM, TO, message)
        server.close()
        print 'successfully sent the mail'
    except:
        print "failed to send mail"

se si desidera utilizzare la porta 465 è necessario creare un SMTP_SSLoggetto:

# SMTP_SSL Example
server_ssl = smtplib.SMTP_SSL("smtp.gmail.com", 465)
server_ssl.ehlo() # optional, called by login()
server_ssl.login(gmail_user, gmail_pwd)  
# ssl server doesn't support or need tls, so don't call server_ssl.starttls() 
server_ssl.sendmail(FROM, TO, message)
#server_ssl.quit()
server_ssl.close()
print 'successfully sent the mail'

2
Campione molto bello grazie. Una cosa che ho notato è che se volessi usare una connessione SSL dovevo rimuovere server.starttls ()
Dowlers

18
Non funziona più, purtroppo: smtplib.SMTPAuthenticationError: (534, '5.7.14 < accounts.google.com/... ... Effettua il login tramite il browser web e \ n5.7.14 riprovare \ n5.7.14 Learn. di più su \ n5.7.14 support.google.com/mail/bin/answer.py?answer=78754 ... Poi ho ricevuto una mail da Google, che si è verificato un tentativo sospetto di connessione
royskatt

13
@royskatt: tutto ciò che devi fare è creare una password per l'app e usarla al posto della password del tuo account. Crea una password per l'app qui: security.google.com/settings/security/apppasswords
Jared

15
@royskatt: ho appena ricevuto una soluzione per il problema che stai affrontando. Google ha un'impostazione per consentire l'accesso per le app meno sicure devi solo accenderlo. puoi arrivarci da: Google -> il mio account -> Accesso e sicurezza -> App e siti collegati -> scorri verso il basso e troverai "Consenti app meno sicure"
shaleen mohan

2
Se il tuo gmail è protetto dall'autenticazione a due fattori, devi prima generare una password specifica per l'applicazione -> quindi utilizza quella password per l'app nel codice di esempio sopra (questo è molto importante perché non stai scrivendo la tua password da nessuna parte in chiaro e puoi revocare la password dell'app in qualsiasi momento).
Trevor Boyd Smith,

136

Mi sono imbattuto in un problema simile e mi sono imbattuto in questa domanda. Ho ricevuto un errore di autenticazione SMTP ma il mio nome utente / pass erano corretti. Ecco cosa l'ha risolto. Ho letto questo:

https://support.google.com/accounts/answer/6010255

In poche parole, google non ti consente di accedere tramite smtplib perché ha contrassegnato questo tipo di accesso come "meno sicuro", quindi quello che devi fare è andare a questo link mentre sei collegato al tuo account google, e consentire l'accesso:

https://www.google.com/settings/security/lesssecureapps

Una volta impostato (vedi il mio screenshot qui sotto), dovrebbe funzionare.

inserisci qui la descrizione dell'immagine

Il login ora funziona:

smtpserver = smtplib.SMTP("smtp.gmail.com", 587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo()
smtpserver.login('me@gmail.com', 'me_pass')

Risposta dopo la modifica:

(235, '2.7.0 Accepted')

Risposta precedente:

smtplib.SMTPAuthenticationError: (535, '5.7.8 Username and Password not accepted. Learn more at\n5.7.8 http://support.google.com/mail/bin/answer.py?answer=14257 g66sm2224117qgf.37 - gsmtp')

Continua a non funzionare?Se ricevi ancora SMTPAuthenticationError ma ora il codice è 534, è perché la posizione è sconosciuta. Segui questo link:

https://accounts.google.com/DisplayUnlockCaptcha

Fai clic su continua e questo dovrebbe darti 10 minuti per la registrazione della tua nuova app. Quindi procedi a fare un altro tentativo di accesso ora e dovrebbe funzionare.

AGGIORNAMENTO : Questo non sembra funzionare immediatamente, potresti rimanere bloccato per un po 'ottenendo questo errore in smptlib:

235 == 'Authentication successful'
503 == 'Error: already authenticated'

Il messaggio dice di usare il browser per accedere:

SMTPAuthenticationError: (534, '5.7.9 Please log in with your web browser and then try again. Learn more at\n5.7.9 https://support.google.com/mail/bin/answer.py?answer=78754 qo11sm4014232igb.17 - gsmtp')

Dopo aver abilitato 'lesssecureapps', vai a prendere un caffè, torna indietro e prova di nuovo il link 'DisplayUnlockCaptcha'. In base all'esperienza utente, l'avvio della modifica potrebbe richiedere fino a un'ora. Quindi riprovare a eseguire la procedura di accesso.


3
SI GRAZIE ! È successo mentre usavo la posta di pallone
Giannis il

1
grazie uomo unico problema per me: accounts.google.com/DisplayUnlockCaptcha
Limitless isa

6
Inoltre, si prega di lasciare mezz'ora a un'ora per modificare le impostazioni. Ho creato un nuovo account, disabilitato tutta la sicurezza aggiunta e ho ancora ricevuto lo stesso errore. Circa un'ora dopo, ha funzionato tutto.
jkgeyti,

2
L'abilitazione di app meno sicure non è possibile se è abilitata la "verifica in due passaggi". L'opzione migliore e più sicura è abilitare "apppassword" security.google.com/settings/security/apppasswords come già suggerito, e funziona come un incantesimo
Omiod

2
Quando seguo il link delle password app, tutti i miei account Google ricevono l'errore "L'impostazione che stai cercando non è disponibile per il tuo account".
Suzanne,

18

Sei giù con OOP?

#!/usr/bin/env python


import smtplib

class Gmail(object):
    def __init__(self, email, password):
        self.email = email
        self.password = password
        self.server = 'smtp.gmail.com'
        self.port = 587
        session = smtplib.SMTP(self.server, self.port)        
        session.ehlo()
        session.starttls()
        session.ehlo
        session.login(self.email, self.password)
        self.session = session

    def send_message(self, subject, body):
        ''' This must be removed '''
        headers = [
            "From: " + self.email,
            "Subject: " + subject,
            "To: " + self.email,
            "MIME-Version: 1.0",
           "Content-Type: text/html"]
        headers = "\r\n".join(headers)
        self.session.sendmail(
            self.email,
            self.email,
            headers + "\r\n\r\n" + body)


gm = Gmail('Your Email', 'Password')

gm.send_message('Subject', 'Message')

33
Se la tua classe ha solo due metodi, uno dei quali è __init__, usa semplicemente una funzione.
JoeQuery,

Come aggiungeresti un allegato usando questo metodo?
sgerbhctim,

L'utilizzo di una classe sarebbe utile se si desidera avviare il client e passarlo ad altre parti del codice, anziché passare un indirizzo e-mail e una password. Oppure se vuoi inviare più messaggi senza passare per email e password ogni volta.
Sami Inizia il

15

Questo funziona

Crea password APP Gmail!

Dopo averlo creato, crea un file chiamato sendgmail.py

Quindi aggiungi questo codice :

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# =============================================================================
# Created By  : Jeromie Kirchoff
# Created Date: Mon Aug 02 17:46:00 PDT 2018
# =============================================================================
# Imports
# =============================================================================
import smtplib

# =============================================================================
# SET EMAIL LOGIN REQUIREMENTS
# =============================================================================
gmail_user = 'THEFROM@gmail.com'
gmail_app_password = 'YOUR-GOOGLE-APPLICATION-PASSWORD!!!!'

# =============================================================================
# SET THE INFO ABOUT THE SAID EMAIL
# =============================================================================
sent_from = gmail_user
sent_to = ['THE-TO@gmail.com', 'THE-TO@gmail.com']
sent_subject = "Where are all my Robot Women at?"
sent_body = ("Hey, what's up? friend!\n\n"
             "I hope you have been well!\n"
             "\n"
             "Cheers,\n"
             "Jay\n")

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

%s
""" % (sent_from, ", ".join(sent_to), sent_subject, sent_body)

# =============================================================================
# SEND EMAIL OR DIE TRYING!!!
# Details: http://www.samlogic.net/articles/smtp-commands-reference.htm
# =============================================================================

try:
    server = smtplib.SMTP_SSL('smtp.gmail.com', 465)
    server.ehlo()
    server.login(gmail_user, gmail_app_password)
    server.sendmail(sent_from, sent_to, email_text)
    server.close()

    print('Email sent!')
except Exception as exception:
    print("Error: %s!\n\n" % exception)

Quindi, se hai successo, vedrai un'immagine come questa:

Ho provato inviando un'e-mail da e verso me stesso.

Email inviata con successo.

Nota: ho attivato la verifica in due passaggi sul mio account. App Password funziona con questo! (per l'installazione di gmail smtp, devi andare su https://support.google.com/accounts/answer/185833?hl=en e seguire i passaggi seguenti)

Questa impostazione non è disponibile per gli account con la verifica in due passaggi abilitata. Tali account richiedono una password specifica per l'applicazione per un accesso meno sicuro alle app.

Accesso meno sicuro all'app ... Questa impostazione non è disponibile per gli account con la verifica in due passaggi abilitata.


1
Soluzione fantastica e molto ben spiegata nel codice. Grazie Jay, molto apprezzato. Domanda stupida: sapresti qual è il limite massimo di email al giorno che potrebbe essere inviato (con Gmail)?
Angelo,

Grazie @Angelo, ma sì, c'è un limite, GMail = 500 email o 500 destinatari / Rif. Giorno: support.google.com/mail/answer/22839 G SUITE è diverso ed è 2000 messaggi / giorno e può essere trovato qui: supporto .google.com / a / answer / 166852 Buona fortuna!
JayRizzo

2
Tutti gli altri sono post precedenti e potrebbero non funzionare, ma questo funziona al 100%. Genera password per le app. Grazie per la risposta
Shubh,

1
Sono un po 'sorpreso che questa soluzione non abbia più voti. Non ho provato tutti gli altri, ma ne ho provati diversi, e solo questo ha funzionato fuori dagli schemi, con armeggiare.
mcouthon,

14

Puoi trovarlo qui: http://jayrambhia.com/blog/send-emails-using-python

smtp_host = 'smtp.gmail.com'
smtp_port = 587
server = smtplib.SMTP()
server.connect(smtp_host,smtp_port)
server.ehlo()
server.starttls()
server.login(user,passw)
fromaddr = raw_input('Send mail by the name of: ')
tolist = raw_input('To: ').split()
sub = raw_input('Subject: ')

msg = email.MIMEMultipart.MIMEMultipart()
msg['From'] = fromaddr
msg['To'] = email.Utils.COMMASPACE.join(tolist)
msg['Subject'] = sub  
msg.attach(MIMEText(raw_input('Body: ')))
msg.attach(MIMEText('\nsent via python', 'plain'))
server.sendmail(user,tolist,msg.as_string())

2
più 1 perché è meglio creare un MIME piuttosto che codificare la propria stringa di formato. MIMEMultipart è richiesto per un semplice messaggio di testo? O è la seguente anche corretta: stackoverflow.com/a/6270987/895245
Ciro Santilli郝海东冠状病六四事件法轮功

Dove installi la variabile e-mail?
madcat,

11

Non direttamente correlato ma comunque degno di nota è che il mio pacchetto cerca di rendere l'invio di messaggi Gmail davvero rapido e indolore. Cerca inoltre di mantenere un elenco di errori e cerca di puntare immediatamente alla soluzione.

Avrebbe letteralmente bisogno solo di questo codice per fare esattamente quello che hai scritto:

import yagmail
yag = yagmail.SMTP('user_me@gmail.com')
yag.send('user_you@gmail.com', 'Why,Oh why!')

O una fodera:

yagmail.SMTP('user_me@gmail.com').send('user_you@gmail.com', 'Why,Oh why!')

Per il pacchetto / installazione, consultare git o pip , disponibili per Python 2 e 3.


9

Ecco un esempio dell'API di Gmail. Anche se più complicato, questo è l'unico metodo che ho trovato che funziona nel 2019. Questo esempio è stato preso e modificato da:

https://developers.google.com/gmail/api/guides/sending

Dovrai creare un progetto con le interfacce API di Google attraverso il loro sito Web. Successivamente dovrai abilitare l'API GMAIL per la tua app. Crea le credenziali e poi scarica quelle credenziali, salvale come credentials.json.

import pickle
import os.path
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request

from email.mime.text import MIMEText
import base64

#pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib

# If modifying these scopes, delete the file token.pickle.
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly', 'https://www.googleapis.com/auth/gmail.send']

def create_message(sender, to, subject, msg):
    message = MIMEText(msg)
    message['to'] = to
    message['from'] = sender
    message['subject'] = subject

    # Base 64 encode
    b64_bytes = base64.urlsafe_b64encode(message.as_bytes())
    b64_string = b64_bytes.decode()
    return {'raw': b64_string}
    #return {'raw': base64.urlsafe_b64encode(message.as_string())}

def send_message(service, user_id, message):
    #try:
    message = (service.users().messages().send(userId=user_id, body=message).execute())
    print( 'Message Id: %s' % message['id'] )
    return message
    #except errors.HttpError, error:print( 'An error occurred: %s' % error )

def main():
    """Shows basic usage of the Gmail API.
    Lists the user's Gmail labels.
    """
    creds = None
    # The file token.pickle stores the user's access and refresh tokens, and is
    # created automatically when the authorization flow completes for the first
    # time.
    if os.path.exists('token.pickle'):
        with open('token.pickle', 'rb') as token:
            creds = pickle.load(token)
    # If there are no (valid) credentials available, let the user log in.
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            flow = InstalledAppFlow.from_client_secrets_file(
                'credentials.json', SCOPES)
            creds = flow.run_local_server(port=0)
        # Save the credentials for the next run
        with open('token.pickle', 'wb') as token:
            pickle.dump(creds, token)

    service = build('gmail', 'v1', credentials=creds)

    # Example read operation
    results = service.users().labels().list(userId='me').execute()
    labels = results.get('labels', [])

    if not labels:
        print('No labels found.')
    else:
        print('Labels:')
    for label in labels:
        print(label['name'])

    # Example write
    msg = create_message("from@gmail.com", "to@gmail.com", "Subject", "Msg")
    send_message( service, 'me', msg)

if __name__ == '__main__':
    main()

smtplib non è completamente thread-safe, quindi avrà problemi con l'invio di messaggi simultanei. Questo è l'approccio giusto.
dsbajna,

2

Ora c'è un'API di Gmail che ti consente di inviare e-mail, leggere e-mail e creare bozze tramite REST. A differenza delle chiamate SMTP, è non bloccante che può essere una buona cosa per i server Web basati su thread che inviano e-mail nel thread della richiesta (come i server Web Python). L'API è anche abbastanza potente.

  • Ovviamente, l'e-mail dovrebbe essere passata a una coda non webserver, ma è bello avere opzioni.

È più semplice da configurare se disponi dei diritti di amministratore di Google Apps sul dominio, perché in questo modo puoi concedere l'autorizzazione generale al tuo client. Altrimenti devi giocherellare con l'autenticazione e l'autorizzazione OAuth.

Ecco un esempio che lo dimostra:

https://gist.github.com/timrichardson/1154e29174926e462b7a


2

ottima risposta di @David, ecco Python 3 senza il generico try-tranne:

def send_email(user, password, recipient, subject, body):

    gmail_user = user
    gmail_pwd = password
    FROM = user
    TO = recipient if type(recipient) is list else [recipient]
    SUBJECT = subject
    TEXT = body

    # Prepare actual message
    message = """From: %s\nTo: %s\nSubject: %s\n\n%s
    """ % (FROM, ", ".join(TO), SUBJECT, TEXT)

    server = smtplib.SMTP("smtp.gmail.com", 587)
    server.ehlo()
    server.starttls()
    server.login(gmail_user, gmail_pwd)
    server.sendmail(FROM, TO, message)
    server.close()

2

Abilita le app meno sicure sul tuo account Gmail e usa (Python> = 3.6):

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

gmailUser = 'XXXXX@gmail.com'
gmailPassword = 'XXXXX'
recipient = 'XXXXX@gmail.com'

message = f"""
Type your message here...
"""

msg = MIMEMultipart()
msg['From'] = f'"Your Name" <{gmailUser}>'
msg['To'] = recipient
msg['Subject'] = "Subject here..."
msg.attach(MIMEText(message))

try:
    mailServer = smtplib.SMTP('smtp.gmail.com', 587)
    mailServer.ehlo()
    mailServer.starttls()
    mailServer.ehlo()
    mailServer.login(gmailUser, gmailPassword)
    mailServer.sendmail(gmailUser, recipient, msg.as_string())
    mailServer.close()
    print ('Email sent!')
except:
    print ('Something went wrong...')

1
Risposta davvero fantastica. Il migliore del gruppo, super conciso. Grazie.
Bruce Dean,

Grazie Pedro, la tua risposta l'ha risolto. A proposito per chiunque usi Gsuite con più alias; aggiungi l'alias al tuo account Gmail seguendo support.google.com/mail/answer/22370?hl=it e puoi inviare utilizzando l'alias sostituendolo <{gmailUser}>con <YourAlias>.
LucSpan

1

Sembra un problema del vecchio smtplib. In python2.7tutto funziona bene.

Aggiornamento : Sì, server.ehlo()potrebbe anche aiutare.


-1
    import smtplib

    fromadd='from@gmail.com'
    toadd='send@gmail.com'

    msg='''hi,how r u'''
    username='abc@gmail.com'
    passwd='password'

    try:
        server = smtplib.SMTP('smtp.gmail.com:587')
        server.ehlo()
        server.starttls()
        server.login(username,passwd)

        server.sendmail(fromadd,toadd,msg)
        print("Mail Send Successfully")
        server.quit()

   except:
        print("Error:unable to send mail")

   NOTE:https://www.google.com/settings/security/lesssecureapps that                                                         should be enabled

Sto pubblicando il semplice codice che farà come inviare la posta dall'account Gmail. Se hai bisogno di informazioni, fammelo sapere. Spero che il codice possa aiutare tutti gli utenti.
Shyam Gupta,

-2
import smtplib
server = smtplib.SMTP('smtp.gmail.com', 587)
server.ehlo()
server.starttls()
server.login("fromaddress", "password")
msg = "HI!"
server.sendmail("fromaddress", "receiveraddress", msg)
server.quit()

codice semplice per inviare una mail tramite Gmail usando il codice Python. da address è il tuo gmailID e destinatarioaddress è id di posta che invii posta
Sam Divya Kumar il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.