Envio de e-mail de Python usando SMTP


118

Estou usando o seguinte método para enviar e-mail de Python usando SMTP. É o método certo a ser usado ou estou perdendo algumas pegadinhas?

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 <john@doe.net>"
to_addr = "foo@bar.com"

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

2
Certifique-se de obter a data / hora correta. Achei a seguinte função bastante útil, que fornece um valor perfeitamente formatado para o Cabeçalho de Data: docs.python.org/py3k/library/…
BastiBen

aqui está um exemplo de código que permite enviar e-mail com texto Unicode no assunto e / ou no corpo
jfs

aqui está um exemplo de código que demonstra como enviar imagens embutidas (mais e-mail com partes de html e texto simples) . Ele também mostra como configurar os parâmetros SSL em versões antigas do Python.
jfs

2
Observe que existem bibliotecas de wrapper disponíveis que tornam muito menos código para enviar e-mails (como yagmail )
PascalVKooten

Respostas:


111

O script que uso é bastante semelhante; Eu o posto aqui como um exemplo de como usar os módulos email. * Para gerar mensagens MIME; portanto, este script pode ser facilmente modificado para anexar imagens, etc.

Conto com meu ISP para adicionar o cabeçalho de data e hora.

Meu ISP exige que eu use uma conexão smtp segura para enviar e-mail, conto com o módulo smtplib (para download em http://www1.cs.columbia.edu/~db2501/ssmtplib.py )

Como em seu script, o nome de usuário e a senha (dados valores fictícios abaixo), usados ​​para autenticar no servidor SMTP, estão em texto simples na fonte. Esta é uma falha de segurança; mas a melhor alternativa depende de quão cuidadoso você precisa (deseja?) para protegê-los.

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

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

1
@Vincent: mail falhou; O objeto 'módulo' não tem atributo 'SSLFakeSocket' - usando o Gmail :(
RadiantHex

Isso soa como um problema de versão ou importação, para ajudar a rastreá-lo: Qual versão do Python você está executando? - Você precisa se conectar ao seu servidor SMTP por SSL (e se sim, você está importando ssmtplib, como acima)? Você pode importar smtplib diretamente do python interativo, em caso afirmativo, há uma classe smtplib.SSLFakeSocket definida? Espero poder ajudar
Vincent Marchetti

2
Use smtplib.SMTP_SSL (padrão nas versões mais recentes do Python) para criar a conexão em vez de ssmtplib.STMP_SSL (módulo de terceiros sugerido acima). Observe que o módulo padrão começa com um único 's'. Isso funcionou para mim.
Julio Gorgé

2
substitua from ssmtplib import SMTP_SSL as SMTPpor from smtplib import SMTP_SSL as SMTP, e este exemplo funcionaria com a biblioteca Python padrão.
Adam Matan

9
Adicione msg['To'] = ','.join(destination), caso contrário, o destino não será visualizado no Gmail
Taha Jahangir

88

O método que normalmente uso ... não muito diferente, mas um pouco

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

msg = MIMEMultipart()
msg['From'] = 'me@gmail.com'
msg['To'] = 'you@gmail.com'
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('me@gmail.com', 'mypassword')

mailserver.sendmail('me@gmail.com','you@gmail.com',msg.as_string())

mailserver.quit()

É isso aí


Se você usar a verificação em duas etapas, deverá primeiro criar uma senha específica do aplicativo e substituir sua senha normal por ela. Consulte Login usando senhas de app
Suzana

2
Eu concordo, essa é a melhor resposta e deve ser aceita. Aquele que é realmente aceito é inferior.
HelloWorld

6
Para python3, use:from email.mime.multipart import MIMEMultipart from email.mime.text import MIMEText
art.

21

Além disso, se você quiser fazer autenticação smtp com TLS ao invés de SSL, então você só precisa mudar a porta (use 587) e fazer smtp.starttls (). Isso funcionou para mim:

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

6

O principal problema que vejo é que você não está lidando com nenhum erro: .login () e .sendmail () têm exceções documentadas que podem lançar e parece que .connect () deve ter alguma forma de indicar que foi incapaz de conectar - provavelmente uma exceção lançada pelo código de soquete subjacente.


6

Certifique-se de não ter nenhum firewall bloqueando o SMTP. A primeira vez que tentei enviar um e-mail, ele foi bloqueado pelo Firewall do Windows e pela McAfee - demorou uma eternidade para encontrar os dois.


6

Que tal isso?

import smtplib

SERVER = "localhost"

FROM = "sender@example.com"
TO = ["user@example.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(SERVER)
server.sendmail(FROM, TO, message)
server.quit()

4

o código a seguir está funcionando bem para mim:

import smtplib

to = 'mkyong2002@yahoo.com'
gmail_user = 'mkyong2002@gmail.com'
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/


1
O Flask tem uma estrutura para email: from flask.ext.mail import Mail. Estou solucionando o problema e pensei em voltar ao código Python para ver se conseguia fazer algo funcionar. Gostei dessa resposta porque era o esqueleto. Oh sim, e funcionou!

Atenção: A versão anterior da resposta incluía a linha: smtpserver.close()Deve ser:, smtpserver.quit()porque close()não encerrará a conexão TLS corretamente! close()será chamado durante quit().
aronadaal

Olá, estou tendo problemas para executar os comandos acima. quando eu uso smtpserver.starttls (), recebo um erro SMTP "SMTPServerDisconnected: Connection inesperadamente encerrado: [Errno 10054]" .. relatado em stackoverflow.com/questions/46094175/…
fazkan


3

O código de exemplo que fiz para enviar e-mail 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()

2

Veja todas aquelas respostas demoradas? Permita que eu me autopromova fazendo tudo isso em algumas linhas.

Importar e conectar:

import yagmail
yag = yagmail.SMTP('john@doe.net', host = 'YOUR.MAIL.SERVER', port = 26)

Então é apenas uma linha:

yag.send('foo@bar.com', 'hello', 'Hello\nThis is a mail from your server\n\nBye\n')

Na verdade, ele fechará quando sair do escopo (ou poderá ser fechado manualmente). Além disso, permitirá que você registre seu nome de usuário em seu chaveiro, de forma que você não precise escrever sua senha em seu script (realmente me incomodou antes de escrever yagmail!)

Para o pacote / instalação, dicas e truques, por favor, dê uma olhada em git ou pip , disponível para Python 2 e 3.


@PascalvKoolen Eu instalei o yagmail e tentei conectar-se fornecendo meu ID de e-mail e senha. mas me deu um erro de autenticação
fazkan

0

você pode fazer assim

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 = 'me@servername.com'
to = 'mygfriend@servername.com'
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)

0

Aqui está um exemplo funcional 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 = 'your_email_address@gmail.com'
password = getpass('Enter Gmail password: ')

sender = 'your_email_address@gmail.com'
destination = 'recipient_email_address@gmail.com'
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)))

0

Com base neste exemplo , criei a seguinte função:

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

se você passar apenas body, o e-mail em texto simples será enviado, mas se você passar o htmlargumento junto com o bodyargumento, o e-mail html será enviado (com fallback para o conteúdo de texto para clientes de e-mail que não suportam os tipos html / mime).

Exemplo de uso:

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

Btw. Se você deseja usar o gmail como servidor SMTP de teste ou produção, habilite o acesso temporário ou permanente a aplicativos menos seguros:

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.