Enviar correo desde Python usando SMTP

118

Estoy usando el siguiente método para enviar correo desde Python usando SMTP. ¿Es el método correcto para usar o hay problemas que me faltan?

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
fuente
2
Asegúrese de obtener la fecha y la hora correctas. Encontré la siguiente función bastante útil, que le brinda un valor perfectamente formateado para el encabezado de fecha: docs.python.org/py3k/library/…
BastiBen
aquí hay un ejemplo de código que demuestra cómo enviar imágenes en línea (más correo electrónico con partes html y texto sin formato) . También muestra cómo configurar parámetros ssl en versiones antiguas de Python.
jfs
2
Tenga en cuenta que hay bibliotecas de envoltura disponibles que hacen que sea mucho menos código para enviar correos electrónicos (como yagmail )
PascalVKooten

Respuestas:

111

El guión que utilizo es bastante similar; Lo publico aquí como un ejemplo de cómo usar los módulos email. * Para generar mensajes MIME; por lo que este script se puede modificar fácilmente para adjuntar imágenes, etc.

Confío en mi ISP para agregar el encabezado de fecha y hora.

Mi ISP requiere que use una conexión smtp segura para enviar correo, confío en el módulo smtplib (descargable en http://www1.cs.columbia.edu/~db2501/ssmtplib.py )

Como en su secuencia de comandos, el nombre de usuario y la contraseña, (dados los valores ficticios a continuación), que se utilizan para autenticarse en el servidor SMTP, están en texto sin formato en la fuente. Esta es una debilidad de seguridad; pero la mejor alternativa depende del cuidado que necesite (¿quiere?) protegerlos.

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

#! /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
fuente
1
@Vincent: error en el correo; El objeto 'módulo' no tiene atributo 'SSLFakeSocket' - usando Gmail :(
RadiantHex
Esto suena como un problema de versión o importación, para ayudar a rastrearlo: ¿Qué versión de Python está ejecutando? - ¿Necesita conectarse a su servidor SMTP a través de SSL (y si es así, está importando ssmtplib, como se indicó anteriormente)? ¿Puede importar smtplib directamente desde python interactivo, si es así, hay una clase smtplib.SSLFakeSocket definida? Espero poder ayudar
Vincent Marchetti
2
Utilice smtplib.SMTP_SSL (estándar en las últimas versiones de Python) para crear la conexión en lugar de ssmtplib.STMP_SSL (módulo de terceros mencionado anteriormente). Observe que el módulo estándar comienza con una sola 's'. Eso funcionó para mí.
Julio Gorgé
2
reemplace from ssmtplib import SMTP_SSL as SMTPcon from smtplib import SMTP_SSL as SMTP, y este ejemplo funcionaría desde la biblioteca estándar de Python.
Adam Matan
9
Agregar msg['To'] = ','.join(destination), de lo contrario, el destino no se ve en gmail
Taha Jahangir
88

El método que uso comúnmente ... no muy diferente pero un poco

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

Eso es

loco2890
fuente
Si usa la verificación en 2 pasos, primero debe crear una contraseña específica de la aplicación y reemplazar su contraseña normal por ella. Consulte Iniciar sesión con contraseñas de aplicaciones
Suzana
2
Estoy de acuerdo, esta es la mejor respuesta y debería aceptarse. El que realmente se acepta es inferior.
HelloWorld
6
Para python3, use:from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
art
21

Además, si desea realizar la autenticación smtp con TLS en lugar de SSL, solo tiene que cambiar el puerto (use 587) y hacer smtp.starttls (). Esto funcionó para mí:

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

fuente
6

El problema principal que veo es que no está manejando ningún error: .login () y .sendmail () ambos tienen excepciones documentadas que pueden lanzar, y parece que .connect () debe tener alguna forma de indicar que fue no se puede conectar, probablemente una excepción lanzada por el código de socket subyacente.

pjz
fuente
6

Asegúrese de no tener ningún firewall que bloquee SMTP. La primera vez que intenté enviar un correo electrónico, fue bloqueado tanto por Firewall de Windows como por McAfee; me tomó una eternidad encontrarlos a ambos.

Mark Ransom
fuente
6

¿Qué pasa con esto?

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
fuente
4

El siguiente código funciona bien para mí:

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

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

Abdul Majeed
fuente
1
Flask tiene un marco para el correo electrónico: desde flask.ext.mail import Mail. Lo estoy solucionando y pensé que volvería al código Python para ver si podía hacer que algo funcionara. Me gustó esta respuesta porque era básica. Oh sí, ¡y funcionó!
Atención: La versión anterior de la respuesta incluía la línea: smtpserver.close()Debe ser:, ¡ smtpserver.quit()porque close()no terminará la conexión TLS correctamente! close()será llamado durante quit().
aronadaal
Hola, tengo problemas para ejecutar los comandos anteriores. cuando uso smtpserver.starttls (), obtengo un error SMTP "SMTPServerDisconnected: Conexión cerrada inesperadamente: [Errno 10054]" .. informado en stackoverflow.com/questions/46094175/…
fazkan
3

Debe asegurarse de formatear la fecha en el formato correcto: RFC2822 .

Douglas Leeder
fuente
3

El código de ejemplo que hice para enviar correo usando 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
fuente
2

¿Ves todas esas extensas respuestas? Permítanme autopromocionarme haciéndolo todo en un par de líneas.

Importar y conectar:

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

Entonces es solo una frase:

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

De hecho, se cerrará cuando salga del alcance (o se puede cerrar manualmente). Además, le permitirá registrar su nombre de usuario en su llavero de modo que no tenga que escribir su contraseña en su script (¡realmente me molestó antes de escribir yagmail!)

Para el paquete / instalación, consejos y trucos, consulte git o pip , disponibles para Python 2 y 3.

PascalVKooten
fuente
@PascalvKoolen Instalé yagmail e intenté conectarme dando mi identificación de correo electrónico y contraseña. pero me dio un error de autenticación
fazkan
0

puedes hacer así

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
fuente
0

Aquí hay un ejemplo de trabajo para 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)))
marca
fuente
0

Basado en este ejemplo hice la siguiente función:

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 solo pasa body, se enviará un correo de texto sin formato, pero si pasa un htmlargumento junto con un bodyargumento, se enviará un correo electrónico html (con respaldo al contenido de texto para los clientes de correo electrónico que no admiten los tipos html / mime).

Uso de ejemplo:

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"

Por cierto. Si desea utilizar gmail como servidor SMTP de prueba o producción, habilite el acceso temporal o permanente a aplicaciones menos seguras:

Robert Lujo
fuente