Comment envoyer un e-mail avec Gmail en tant que fournisseur en utilisant Python?


289

J'essaie d'envoyer des e-mails (Gmail) à l'aide de python, mais j'obtiens l'erreur suivante.

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.

Le script Python est le suivant.

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
Cette question devrait être déverrouillée maintenant que Google se dirige vers une API interne pour l'envoi de messages via gmail. Cette décision rend toutes ces réponses, sauf une, dépassées, et la seule réponse pertinente est très légère pour résoudre réellement le problème.
Andrew

De plus, pour les utilisateurs VPN, si le problème persiste, désactivez votre VPN. Cela a fonctionné pour moi.
Paul

Réponses:


211

Vous devez dire EHLOavant de vous lancer directement dans STARTTLS:

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

Vous devez également créer des From:en To:- Subject:têtes de message, séparés du corps du message par une ligne vierge et les utiliser CRLFcomme marqueurs EOL.

Par exemple

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

2
invoquant server.sendmail (fromaddr, toaddrs, msg) le deuxième paramètre, toaddrs doit être une liste, toaddrs = ['user_me@gmail.com']
Massimo Fazzolari

14
En août 2014, cela soulève maintenant smtplib.SMTPAuthenticationError: (534, '5.7.9 Mot de passe spécifique à l'application requis.
anon58192932

7
Pour moi cependant, j'ai dû activer un mot de passe «app» pour me connecter en utilisant un compte @google pour envoyer des e-mails via python: support.google.com/accounts/answer/…
anon58192932

1
Voici un lien sur la façon d'envoyer du courrier à plusieurs personnes: stackoverflow.com/questions/8856117/…
anon58192932

1
Une fois, je me suis connecté à un serveur SMTP par telnet et envoyé EHLOpar faute de frappe. Après avoir essayé HELO plusieurs fois, la réponse a été différente. Il a fallu des heures pour comprendre qu'EHLO est en fait une commande que SMTP comprend et j'ai fait la faute de frappe.
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"

si vous souhaitez utiliser le port 465, vous devez créer un SMTP_SSLobjet:

# 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
Très bel échantillon merci. Je pense que j'ai remarqué que si je veux utiliser une connexion SSL, je devais supprimer server.starttls ()
Dowlers

18
Malheureusement, ne fonctionne plus: smtplib.SMTPAuthenticationError: (534, '5.7.14 < accounts.google.com/… ... Veuillez vous connecter via votre navigateur Web et \ n5.7.14 puis réessayer. \ N5.7.14 En savoir plus sur \ n5.7.14 support.google.com/mail/bin/answer.py?answer=78754 ... Ensuite, j'ai reçu un e-mail de google, indiquant qu'il y a eu une tentative de connexion suspecte.
royskatt

13
@royskatt - il vous suffit de créer un mot de passe d'application et de l'utiliser à la place du mot de passe de votre compte. Créez un mot de passe d'application ici: security.google.com/settings/security/apppasswords
Jared

15
@royskatt: Je viens de recevoir un correctif pour le problème auquel vous faisiez face. Google a un paramètre pour autoriser l'accès à des applications moins sécurisées, il vous suffit de l'activer. vous pouvez y accéder à partir de: Google -> mon compte -> Connexion et sécurité -> Applications et sites connectés -> faites défiler vers le bas et vous trouverez «Autoriser les applications moins sécurisées»
shaleen mohan

2
Si votre gmail est sécurisé par l'authentification à deux facteurs, vous devez d'abord générer un mot de passe spécifique à l'application -> puis utiliser ce mot de passe d'application pour dans l'exemple de code ci-dessus (cela est très important car vous n'écrivez votre mot de passe nulle part en texte clair ET vous pouvez révoquer le mot de passe de l'application à tout moment).
Trevor Boyd Smith

136

J'ai rencontré un problème similaire et suis tombé sur cette question. J'ai obtenu une erreur d'authentification SMTP mais mon nom d'utilisateur / mot de passe était correct. Voici ce qui l'a corrigé. J'ai lu ceci:

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

En un mot, Google ne vous permet pas de vous connecter via smtplib car il a marqué ce type de connexion comme "moins sécurisé", donc ce que vous avez à faire est d'aller sur ce lien pendant que vous êtes connecté à votre compte Google, et permettre l'accès:

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

Une fois cela réglé (voir ma capture d'écran ci-dessous), cela devrait fonctionner.

entrez la description de l'image ici

La connexion fonctionne maintenant:

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

Réponse après changement:

(235, '2.7.0 Accepted')

Réponse préalable:

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')

Ne fonctionne toujours pas? Si vous obtenez toujours le SMTPAuthenticationError mais que maintenant le code est 534, c'est parce que l'emplacement est inconnu. Suivez ce lien:

https://accounts.google.com/DisplayUnlockCaptcha

Cliquez sur Continuer et cela devrait vous donner 10 minutes pour enregistrer votre nouvelle application. Continuez donc à faire une autre tentative de connexion maintenant et cela devrait fonctionner.

MISE À JOUR : Cela ne semble pas fonctionner tout de suite, vous pouvez être bloqué pendant un certain temps en obtenant cette erreur dans smptlib:

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

Le message indique d'utiliser le navigateur pour se connecter:

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')

Après avoir activé 'lesssecureapps', allez prendre un café, revenez et essayez à nouveau le lien 'DisplayUnlockCaptcha'. D'après l'expérience utilisateur, le changement peut prendre jusqu'à une heure. Puis essayez à nouveau de vous connecter.


3
OUI MERCI ! Arrivé en utilisant flask-mail
Giannis

1
merci homme seul problème pour moi: accounts.google.com/DisplayUnlockCaptcha
Limitless isa

6
De plus, veuillez laisser une demi-heure à une heure pour que les paramètres changent. J'ai créé un nouveau compte, désactivé toute la sécurité supplémentaire et j'ai toujours la même erreur. Environ une heure plus tard, tout a fonctionné.
jkgeyti

2
L'activation d'applications moins sécurisées n'est pas possible si la «vérification en deux étapes» est activée. L'option la meilleure et la plus sécurisée consiste à activer le "apppassword" security.google.com/settings/security/apppasswords comme déjà suggéré, et cela fonctionne comme un charme
Omiod

2
Lorsque je suis le lien apppasswords, tous mes comptes Google obtiennent une erreur «Le paramètre que vous recherchez n'est pas disponible pour votre compte».
Suzanne

18

Vous en bas avec 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
Si votre classe n'a que deux méthodes, dont l'une est __init__, utilisez simplement une fonction.
JoeQuery

Comment ajouteriez-vous une pièce jointe en utilisant cette méthode?
sgerbhctim

Utiliser une classe serait bien si vous vouliez initier le client et le transmettre à d'autres parties du code, au lieu de passer un e-mail et un mot de passe. Ou si vous souhaitez envoyer plusieurs messages sans passer à chaque fois par e-mail et mot de passe.
Sami Start

15

Cela marche

Créez le mot de passe de l'application Gmail!

Après avoir créé cela, créez un fichier appelé sendgmail.py

Ajoutez ensuite ce code :

#!/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)

Donc, si vous réussissez, vous verrez une image comme celle-ci:

J'ai testé en envoyant un e-mail depuis et vers moi-même.

E-mail envoyé avec succès.

Remarque: la validation en deux étapes est activée sur mon compte. Le mot de passe de l'application fonctionne avec cela! (pour la configuration de smtp gmail, vous devez vous rendre sur https://support.google.com/accounts/answer/185833?hl=en et suivre les étapes ci-dessous)

Ce paramètre n'est pas disponible pour les comptes avec la vérification en deux étapes activée. Ces comptes nécessitent un mot de passe spécifique à l'application pour un accès aux applications moins sécurisé.

Accès aux applications moins sécurisé ... Ce paramètre n'est pas disponible pour les comptes avec la validation en deux étapes activée.


1
Solution fantastique et très bien expliquée dans le code. Merci Jay, très apprécié. Question stupide: savez-vous quelle est la limite maximale d'e-mails par jour pouvant être envoyés (avec gmail)?
Angelo

Merci @Angelo mais oui il y a une limite, GMail = 500 emails ou 500 destinataires / jour ref: support.google.com/mail/answer/22839 G SUITE est différent et fait 2000 messages / jour et peut être trouvé ici: support .google.com / a / answer / 166852 Bonne chance!
JayRizzo

2
Tous les autres sont des postes plus anciens et peuvent ne pas fonctionner, mais cela fonctionne à 100%. Générez des mots de passe d'application. Merci pour la réponse
Shubh

1
Je suis un peu surpris que cette solution n'ait pas plus de votes positifs. Je n'ai pas essayé tous les autres, mais j'en ai essayé plusieurs, et seulement celui-ci a fonctionné hors de la boîte, avec 0 bricolage.
mcouthon le

14

Vous pouvez le trouver ici: 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
plus 1 car il vaut mieux construire un MIME que de coder en dur votre propre chaîne de format. MIMEMultipart est-il requis pour un simple message texte? Ou est-ce également correct: stackoverflow.com/a/6270987/895245
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Où instanciez-vous la variable e-mail?
madcat le

11

Ce n'est pas directement lié, mais il vaut la peine de le souligner, mon paquet essaie de rendre l'envoi de messages gmail très rapide et indolore. Il essaie également de maintenir une liste d'erreurs et essaie de pointer vers la solution immédiatement.

Il n'aurait besoin que de ce code pour faire exactement ce que vous avez écrit:

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

Ou une doublure:

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

Pour le package / l'installation, veuillez consulter git ou pip , disponible pour Python 2 et 3.


9

Voici un exemple d'API Gmail. Bien que plus compliqué, c'est la seule méthode que j'ai trouvée qui fonctionne en 2019. Cet exemple a été pris et modifié à partir de:

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

Vous devrez créer un projet avec les interfaces API de Google via leur site Web. Vous devrez ensuite activer l'API GMAIL pour votre application. Créez des informations d'identification, puis téléchargez ces informations d'identification, enregistrez-les sous 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 n'est pas entièrement thread-safe, il aura donc des problèmes pour envoyer des messages simultanés. C'est la bonne approche.
dsbajna

2

Il existe maintenant une API gmail, qui vous permet d'envoyer des e-mails, de lire des e-mails et de créer des brouillons via REST. Contrairement aux appels SMTP, il est non bloquant, ce qui peut être une bonne chose pour les serveurs Web basés sur des threads qui envoient des e-mails dans le thread de demande (comme les serveurs Web Python). L'API est également assez puissante.

  • Bien sûr, les e-mails doivent être transférés vers une file d'attente autre qu'un serveur Web, mais il est agréable d'avoir des options.

Il est plus facile à configurer si vous avez des droits d'administrateur Google Apps sur le domaine, car vous pouvez alors accorder une autorisation générale à votre client. Sinon, vous devez jouer avec l'authentification et l'autorisation OAuth.

Voici un résumé qui le démontre:

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


2

excellente réponse de @David, voici pour Python 3 sans le try-except générique:

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

Activez des applications moins sécurisées sur votre compte Gmail et utilisez (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
Réponse vraiment fantastique. Le meilleur du groupe, super concis. Je vous remercie.
Bruce Dean

Merci Pedro, votre réponse l'a résolu. Btw pour toute personne utilisant Gsuite avec plusieurs alias; ajoutez simplement l'alias à votre compte gmail en suivant support.google.com/mail/answer/22370?hl=en et vous pouvez envoyer en utilisant l'alias en le remplaçant <{gmailUser}>par <YourAlias>.
LucSpan

1

Semble comme un problème de l'ancien smtplib. Dans python2.7tout fonctionne bien.

Mise à jour : Oui, server.ehlo()pourrait également aider.


-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

Je publie le code simple qui fera comment envoyer du courrier à partir du compte Gmail. Si vous avez besoin d'informations, faites-le moi savoir. J'espère que ce code aidera tous les utilisateurs.
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()

code simple pour envoyer un courrier via gmail en utilisant du code python. à partir de l'adresse est votre gmailID et receiveraddress est l'identifiant de messagerie que vous envoyez.
Sam Divya Kumar
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.