Envoi de courrier depuis Python en utilisant SMTP

118

J'utilise la méthode suivante pour envoyer du courrier à partir de Python en utilisant SMTP. Est-ce la bonne méthode à utiliser ou y a-t-il des pièges qui me manquent?

from smtplib import SMTP
import datetime

debuglevel = 0

smtp = SMTP()
smtp.set_debuglevel(debuglevel)
smtp.connect('YOUR.MAIL.SERVER', 26)
smtp.login('USERNAME@DOMAIN', 'PASSWORD')

from_addr = "John Doe <[email protected]>"
to_addr = "[email protected]"

subj = "hello"
date = datetime.datetime.now().strftime( "%d/%m/%Y %H:%M" )

message_text = "Hello\nThis is a mail from your server\n\nBye\n"

msg = "From: %s\nTo: %s\nSubject: %s\nDate: %s\n\n%s" 
        % ( from_addr, to_addr, subj, date, message_text )

smtp.sendmail(from_addr, to_addr, msg)
smtp.quit()
Eli Bendersky
la source
2
Assurez-vous que la date et l'heure sont correctes. J'ai trouvé la fonction suivante assez utile, qui vous donne une valeur parfaitement formatée pour l'en-tête de date: docs.python.org/py3k/library
...
voici un exemple de code qui montre comment envoyer des images en ligne (plus un courrier électronique avec des parties html et texte brut) . Il montre également comment configurer les paramètres ssl sur les anciennes versions de Python.
jfs
2
Notez qu'il existe des bibliothèques de wrapper disponibles qui en font beaucoup moins de code pour envoyer des e-mails (comme yagmail )
PascalVKooten

Réponses:

111

Le script que j'utilise est assez similaire; Je le poste ici comme exemple d'utilisation des modules email. * Pour générer des messages MIME; donc ce script peut être facilement modifié pour joindre des images, etc.

Je compte sur mon FAI pour ajouter l'en-tête de date et d'heure.

Mon FAI me demande d'utiliser une connexion smtp sécurisée pour envoyer du courrier, je compte sur le module smtplib (téléchargeable sur http://www1.cs.columbia.edu/~db2501/ssmtplib.py )

Comme dans votre script, le nom d'utilisateur et le mot de passe (donnés ci-dessous), utilisés pour s'authentifier sur le serveur SMTP, sont en texte brut dans la source. C'est une faiblesse de sécurité; mais la meilleure alternative dépend de la prudence dont vous avez besoin (voulez?) pour les protéger.

========================================

#! /usr/local/bin/python


SMTPserver = 'smtp.att.yahoo.com'
sender =     'me@my_email_domain.net'
destination = ['recipient@her_email_domain.com']

USERNAME = "USER_NAME_FOR_INTERNET_SERVICE_PROVIDER"
PASSWORD = "PASSWORD_INTERNET_SERVICE_PROVIDER"

# typical values for text_subtype are plain, html, xml
text_subtype = 'plain'


content="""\
Test message
"""

subject="Sent from Python"

import sys
import os
import re

from smtplib import SMTP_SSL as SMTP       # this invokes the secure SMTP protocol (port 465, uses SSL)
# from smtplib import SMTP                  # use this for standard SMTP protocol   (port 25, no encryption)

# old version
# from email.MIMEText import MIMEText
from email.mime.text import MIMEText

try:
    msg = MIMEText(content, text_subtype)
    msg['Subject']=       subject
    msg['From']   = sender # some SMTP servers will do this automatically, not all

    conn = SMTP(SMTPserver)
    conn.set_debuglevel(False)
    conn.login(USERNAME, PASSWORD)
    try:
        conn.sendmail(sender, destination, msg.as_string())
    finally:
        conn.quit()

except:
    sys.exit( "mail failed; %s" % "CUSTOM_ERROR" ) # give an error message
Vincent Marchetti
la source
1
@Vincent: échec du courrier; L'objet 'module' n'a pas d'attribut 'SSLFakeSocket' - en utilisant Gmail :(
RadiantHex
Cela ressemble à un problème de version ou d'importation, pour aider à le localiser: Quelle version de Python utilisez-vous? - Devez-vous vous connecter à votre serveur SMTP via SSL (et si oui importez-vous ssmtplib, comme ci-dessus)? Pouvez-vous importer smtplib directement à partir de python interactive, si oui, y a-t-il une classe smtplib.SSLFakeSocket définie? J'espère que je peux aider
Vincent Marchetti
2
Utilisez smtplib.SMTP_SSL (standard dans les dernières versions de Python) pour créer la connexion au lieu de ssmtplib.STMP_SSL (module tiers mentionné ci-dessus). Notez que le module standard commence par un seul «s». Cela a fonctionné pour moi.
Julio Gorgé
2
remplacez from ssmtplib import SMTP_SSL as SMTPpar from smtplib import SMTP_SSL as SMTP, et cet exemple fonctionnerait à partir de la bibliothèque Python standard.
Adam Matan
9
Ajouter msg['To'] = ','.join(destination), sinon la destination n'est pas affichée dans gmail
Taha Jahangir
88

La méthode que j'utilise couramment ... pas très différente mais un peu

import smtplib
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText

msg = MIMEMultipart()
msg['From'] = '[email protected]'
msg['To'] = '[email protected]'
msg['Subject'] = 'simple email in python'
message = 'here is the email'
msg.attach(MIMEText(message))

mailserver = smtplib.SMTP('smtp.gmail.com',587)
# identify ourselves to smtp gmail client
mailserver.ehlo()
# secure our email with tls encryption
mailserver.starttls()
# re-identify ourselves as an encrypted connection
mailserver.ehlo()
mailserver.login('[email protected]', 'mypassword')

mailserver.sendmail('[email protected]','[email protected]',msg.as_string())

mailserver.quit()

C'est tout

fou2890
la source
Si vous utilisez la vérification en 2 étapes, vous devez d'abord créer un mot de passe spécifique à l'application et remplacer votre mot de passe normal par celui-ci. Voir Se connecter avec des mots de passe d'application
Suzana
2
Je suis d'accord, c'est la meilleure réponse et devrait être acceptée. Celui qui est réellement accepté est inférieur.
HelloWorld
7
Pour python3, utilisez:from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
art
21

De plus, si vous voulez faire l'authentification smtp avec TLS par opposition à SSL, il vous suffit de changer le port (utilisez 587) et de faire smtp.starttls (). Cela a fonctionné pour moi:

...
smtp.connect('YOUR.MAIL.SERVER', 587)
smtp.ehlo()
smtp.starttls()
smtp.ehlo()
smtp.login('USERNAME@DOMAIN', 'PASSWORD')
...

la source
6

Le principal inconvénient que je vois est que vous ne gérez aucune erreur: .login () et .sendmail () ont tous deux des exceptions documentées qu'ils peuvent lancer, et il semble que .connect () doit avoir un moyen d'indiquer que c'était impossible de se connecter - probablement une exception levée par le code de socket sous-jacent.

pjz
la source
6

Assurez-vous qu'aucun pare-feu ne bloque SMTP. La première fois que j'ai essayé d'envoyer un e-mail, il a été bloqué à la fois par le pare-feu Windows et McAfee - il a fallu une éternité pour les trouver tous les deux.

Mark Ransom
la source
6

Et ça?

import smtplib

SERVER = "localhost"

FROM = "[email protected]"
TO = ["[email protected]"] # 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(SERVER)
server.sendmail(FROM, TO, message)
server.quit()
Satish
la source
4

le code suivant fonctionne bien pour moi:

import smtplib

to = '[email protected]'
gmail_user = '[email protected]'
gmail_pwd = 'yourpassword'
smtpserver = smtplib.SMTP("smtp.gmail.com",587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo() # extra characters to permit edit
smtpserver.login(gmail_user, gmail_pwd)
header = 'To:' + to + '\n' + 'From: ' + gmail_user + '\n' + 'Subject:testing \n'
print header
msg = header + '\n this is test msg from mkyong.com \n\n'
smtpserver.sendmail(gmail_user, to, msg)
print 'done!'
smtpserver.quit()

Réf: http://www.mkyong.com/python/how-do-send-email-in-python-via-smtplib/

Abdul Majeed
la source
1
Flask a un cadre pour le courrier électronique: à partir de flask.ext.mail import Mail. Je suis en train de le dépanner et j'ai pensé que je retournerais au code Python pour voir si je pouvais faire fonctionner quelque chose. J'ai aimé cette réponse parce qu'elle était épurée. Oh ouais, et ça a marché!
Attention: La version précédente de la réponse incluait la ligne: smtpserver.close()Cela doit être:, smtpserver.quit()car close()ne mettra pas fin à la connexion TLS correctement! close()sera appelé pendant quit().
aronadaal
Salut, j'ai du mal à exécuter les commandes ci-dessus. lorsque j'utilise smtpserver.starttls (), j'obtiens une erreur SMTP "SMTPServerDisconnected: Connexion fermée de manière inattendue: [Errno 10054]" .. signalé dans stackoverflow.com/questions/46094175/…
fazkan
3

Vous devez vous assurer de formater la date dans le format correct - RFC2822 .

Douglas Leeder
la source
3

L'exemple de code que j'ai fait pour envoyer du courrier en utilisant SMTP.

import smtplib, ssl

smtp_server = "smtp.gmail.com"
port = 587  # For starttls
sender_email = "sender@email"
receiver_email = "receiver@email"
password = "<your password here>"
message = """ Subject: Hi there

This message is sent from Python."""


# Create a secure SSL context
context = ssl.create_default_context()

# Try to log in to server and send email
server = smtplib.SMTP(smtp_server,port)

try:
    server.ehlo() # Can be omitted
    server.starttls(context=context) # Secure the connection
    server.ehlo() # Can be omitted
    server.login(sender_email, password)
    server.sendmail(sender_email, receiver_email, message)
except Exception as e:
    # Print any error messages to stdout
    print(e)
finally:
    server.quit()
Hariharan AR
la source
2

Voir toutes ces réponses longues? S'il vous plaît, permettez-moi de me promouvoir en faisant tout cela en quelques lignes.

Importez et connectez:

import yagmail
yag = yagmail.SMTP('[email protected]', host = 'YOUR.MAIL.SERVER', port = 26)

Ensuite, ce n'est qu'une seule ligne:

yag.send('[email protected]', 'hello', 'Hello\nThis is a mail from your server\n\nBye\n')

Il se fermera en fait lorsqu'il sortira de sa portée (ou pourra être fermé manuellement). De plus, cela vous permettra d'enregistrer votre nom d'utilisateur dans votre trousseau de clés afin que vous n'ayez pas à écrire votre mot de passe dans votre script (cela m'a vraiment dérangé avant d'écrire yagmail!)

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

PascalVKooten
la source
@PascalvKoolen J'ai installé yagmail et essayé de me connecter en donnant mon identifiant et mon mot de passe. mais cela m'a donné une erreur d'authentification
fazkan
0

tu peux faire comme ça

import smtplib
from email.mime.text import MIMEText
from email.header import Header


server = smtplib.SMTP('mail.servername.com', 25)
server.ehlo()
server.starttls()

server.login('username', 'password')
from = '[email protected]'
to = '[email protected]'
body = 'That A Message For My Girl Friend For tell Him If We will go to eat Something This Nigth'
subject = 'Invite to A Diner'
msg = MIMEText(body,'plain','utf-8')
msg['Subject'] = Header(subject, 'utf-8')
msg['From'] = Header(from, 'utf-8')
msg['To'] = Header(to, 'utf-8')
message = msg.as_string()
server.sendmail(from, to, message)
Skiller Dz
la source
0

Voici un exemple de travail pour Python 3.x

#!/usr/bin/env python3

from email.message import EmailMessage
from getpass import getpass
from smtplib import SMTP_SSL
from sys import exit

smtp_server = 'smtp.gmail.com'
username = '[email protected]'
password = getpass('Enter Gmail password: ')

sender = '[email protected]'
destination = '[email protected]'
subject = 'Sent from Python 3.x'
content = 'Hello! This was sent to you via Python 3.x!'

# Create a text/plain message
msg = EmailMessage()
msg.set_content(content)

msg['Subject'] = subject
msg['From'] = sender
msg['To'] = destination

try:
    s = SMTP_SSL(smtp_server)
    s.login(username, password)
    try:
        s.send_message(msg)
    finally:
        s.quit()

except Exception as E:
    exit('Mail failed: {}'.format(str(E)))
marque
la source
0

Sur la base de cet exemple, j'ai créé la fonction suivante:

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

def send_email(host, port, user, pwd, recipients, subject, body, html=None, from_=None):
    """ copied and adapted from
        /programming/10147455/how-to-send-an-email-with-gmail-as-provider-using-python#12424439
    returns None if all ok, but if problem then returns exception object
    """

    PORT_LIST = (25, 587, 465)

    FROM = from_ if from_ else user 
    TO = recipients if isinstance(recipients, (list, tuple)) else [recipients]
    SUBJECT = subject
    TEXT = body.encode("utf8") if isinstance(body, unicode) else body
    HTML = html.encode("utf8") if isinstance(html, unicode) else html

    if not html:
        # Prepare actual message
        message = """From: %s\nTo: %s\nSubject: %s\n\n%s
        """ % (FROM, ", ".join(TO), SUBJECT, TEXT)
    else:
                # /programming/882712/sending-html-email-using-python#882770
        msg = MIMEMultipart('alternative')
        msg['Subject'] = SUBJECT
        msg['From'] = FROM
        msg['To'] = ", ".join(TO)

        # Record the MIME types of both parts - text/plain and text/html.
        # utf-8 -> /programming/5910104/python-how-to-send-utf-8-e-mail#5910530
        part1 = MIMEText(TEXT, 'plain', "utf-8")
        part2 = MIMEText(HTML, 'html', "utf-8")

        # Attach parts into message container.
        # According to RFC 2046, the last part of a multipart message, in this case
        # the HTML message, is best and preferred.
        msg.attach(part1)
        msg.attach(part2)

        message = msg.as_string()


    try:
        if port not in PORT_LIST: 
            raise Exception("Port %s not one of %s" % (port, PORT_LIST))

        if port in (465,):
            server = smtplib.SMTP_SSL(host, port)
        else:
            server = smtplib.SMTP(host, port)

        # optional
        server.ehlo()

        if port in (587,): 
            server.starttls()

        server.login(user, pwd)
        server.sendmail(FROM, TO, message)
        server.close()
        # logger.info("SENT_EMAIL to %s: %s" % (recipients, subject))
    except Exception, ex:
        return ex

    return None

si vous passez seulement body, un courrier en texte brut sera envoyé, mais si vous passez un htmlargument avecbody argument, un courrier électronique html sera envoyé (avec un retour au contenu texte pour les clients de messagerie qui ne prennent pas en charge les types html / mime).

Exemple d'utilisation:

ex = send_email(
      host        = 'smtp.gmail.com'
   #, port        = 465 # OK
    , port        = 587  #OK
    , user        = "[email protected]"
    , pwd         = "xxx"
    , from_       = '[email protected]'
    , recipients  = ['[email protected]']
    , subject     = "Test from python"
    , body        = "Test from python - body"
    )
if ex: 
    print("Mail sending failed: %s" % ex)
else:
    print("OK - mail sent"

Btw. Si vous souhaitez utiliser gmail comme serveur SMTP de test ou de production, activez l'accès temporaire ou permanent aux applications moins sécurisées:

Robert Lujo
la source