Como enviar um email com o Gmail como provedor usando Python?

289

Estou tentando enviar email (Gmail) usando python, mas estou recebendo o seguinte erro.

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.

O script Python é o seguinte.

import smtplib
fromaddr = '[email protected]'
toaddrs  = '[email protected]'
msg = 'Why,Oh why!'
username = '[email protected]'
password = 'pwd'
server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls()
server.login(username,password)
server.sendmail(fromaddr, toaddrs, msg)
server.quit()
Mahori
fonte
16
Esta questão deve ser desbloqueada agora que o Google está se movendo em direção a uma API interna para enviar mensagens via gmail. Essa ação desatualiza todas as respostas, exceto uma, e a única resposta relevante é muito clara para realmente resolver o problema.
Andrew
Além disso, para usuários de VPN, se o problema persistir, desative sua VPN. Isso funcionou para mim.
Paul

Respostas:

211

Você precisa dizer EHLOantes de executar diretamente STARTTLS:

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

Além disso, você deve realmente criar From:, To:e Subject:cabeçalhos de mensagens, separados do corpo da mensagem por uma linha em branco e usarCRLF los como marcadores de EOL.

Por exemplo

msg = "\r\n".join([
  "From: [email protected]",
  "To: [email protected]",
  "Subject: Just a message",
  "",
  "Why, oh why"
  ])
MattH
fonte
2
invocando server.sendmail (fromaddr, toaddrs, msg) o segundo parâmetro, toaddrs deve ser uma lista, toaddrs = [ '[email protected]']
Massimo Fazzolari
14
A partir de agosto de 2014, isso agora gera smtplib.SMTPAuthenticationError: (534, '5.7.9 é necessária uma senha específica do aplicativo.
anon58192932
7
Para mim, eu tive que habilitar uma senha de 'aplicativo' para fazer login usando uma conta @google para enviar e-mails via python: support.google.com/accounts/answer/…
anon58192932
1
Aqui está um link sobre como enviar e-mail para várias pessoas: stackoverflow.com/questions/8856117/…
anon58192932
1
Uma vez, entrei em um servidor SMTP por telnet e enviei EHLOpor erro de digitação. Depois que eu tentei o HELO muitas vezes, mas a resposta foi diferente. Demorou horas para descobrir que o EHLO é realmente um comando que o SMTP entende e eu fiz o erro de digitação.
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 você quiser usar a porta 465, precisará criar um SMTP_SSLobjeto:

# 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'
David Okwii
fonte
2
Amostra muito agradável obrigado. Um acha que eu notei é se eu quiser usar uma conexão SSL eu tinha que remover server.starttls ()
Dowlers
18
Infelizmente, não funciona mais: smtplib.SMTPAuthenticationError: (534, '5.7.14 < accounts.google.com/… ... Faça login no navegador da web e \ n5.7.14 e tente novamente. \ N5.7.14 Saiba mais mais em \ n5.7.14 support.google.com/mail/bin/answer.py?answer=78754 ... Então recebi um e-mail do google informando que houve uma tentativa de conexão suspeita.
royskatt
13
@royskatt - tudo o que você precisa fazer é criar uma senha do aplicativo e usá-la no lugar da senha da sua conta. Crie uma senha de aplicativo aqui: security.google.com/settings/security/apppasswords
Jared
15
@royskatt: Acabei de receber uma correção para o problema que você estava enfrentando. O Google tem uma configuração para permitir o acesso a aplicativos menos seguros, basta ativá-lo. você pode chegar lá a partir de: Google -> minha conta -> Sign-in e segurança -> aplicativos e sites conectados -> role para baixo e você vai encontrar 'Permitir aplicações menos seguras'
Shaleen mohan
2
Se o seu gmail é protegido pela autenticação de dois fatores, você deve primeiro gerar uma senha específica do aplicativo -> e usar essa senha do aplicativo no código de exemplo acima (isso é muito importante porque você não está escrevendo sua senha em nenhum lugar em texto não criptografado E você pode revogar a senha do aplicativo a qualquer momento).
Trevor Boyd Smith
136

Encontrei um problema semelhante e me deparei com essa questão. Recebi um erro de autenticação SMTP, mas meu nome de usuário / senha estava correto. Aqui está o que foi corrigido. Eu li o seguinte:

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

Em poucas palavras, o Google não permite que você faça login via smtplib porque sinalizou esse tipo de login como "menos seguro". Portanto, o que você precisa fazer é acessar este link enquanto estiver conectado à sua conta do Google, e permita o acesso:

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

Uma vez definido (veja minha captura de tela abaixo), ele deve funcionar.

insira a descrição da imagem aqui

O login agora funciona:

smtpserver = smtplib.SMTP("smtp.gmail.com", 587)
smtpserver.ehlo()
smtpserver.starttls()
smtpserver.ehlo()
smtpserver.login('[email protected]', 'me_pass')

Resposta após alteração:

(235, '2.7.0 Accepted')

Resposta prévia:

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

Ainda não funciona? Se você ainda obtiver o SMTPAuthenticationError, mas agora o código for 534, é porque o local é desconhecido. Siga este link:

https://accounts.google.com/DisplayUnlockCaptcha

Clique em continuar e isso deve lhe dar 10 minutos para registrar seu novo aplicativo. Portanto, continue fazendo outra tentativa de login agora e deve funcionar.

UPDATE : Isso parece não funcionar imediatamente. Você pode ficar parado por um tempo recebendo esse erro no smptlib:

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

A mensagem diz para usar o navegador para entrar:

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

Depois de ativar o 'lesssecureapps', tome um café, volte e tente o link 'DisplayUnlockCaptcha' novamente. Pela experiência do usuário, pode levar até uma hora para que a alteração seja iniciada. Em seguida, tente o processo de login novamente.

Radtek
fonte
3
SIM OBRIGADO! Aconteceu durante o uso do flask-mail
Giannis
1
obrigado cara único problema para mim: accounts.google.com/DisplayUnlockCaptcha
Isit ilimitado
6
Além disso, deixe de meia hora a uma hora para que as configurações sejam alteradas. Criei uma nova conta, desabilitei toda a segurança adicionada e ainda recebi o mesmo erro. Cerca de uma hora depois, tudo funcionou.
Jkgeyti 29/03/16
2
A ativação de aplicativos menos seguros não é possível se você tiver a "Verificação em duas etapas" ativada. A melhor e mais segura opção é permitir que os "apppassword" security.google.com/settings/security/apppasswords como já foi sugerido, e funciona como um encanto
Omiod
2
Quando sigo o link apppasswords, todas as minhas contas do Google recebem o erro "A configuração que você está procurando não está disponível para a sua conta".
Suzanne
18

Você está com 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')
Ricky Wilson
fonte
33
Se sua classe tiver apenas dois métodos, um dos quais é __init__, basta usar uma função.
JoeQuery
Como você adicionaria um anexo usando esse método?
precisa saber é o seguinte
Usar uma classe seria bom se você quisesse iniciar o cliente e passá-lo para outras partes do código, em vez de passar um e-mail e senha. Ou se você quiser enviar várias mensagens sem passar o email e a senha a cada vez.
Sami Iniciar
15

Isso funciona

Crie a senha do aplicativo do Gmail!

Depois de criar isso, crie um arquivo chamado sendgmail.py

Em seguida, adicione este código :

#!/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 = '[email protected]'
gmail_app_password = 'YOUR-GOOGLE-APPLICATION-PASSWORD!!!!'

# =============================================================================
# SET THE INFO ABOUT THE SAID EMAIL
# =============================================================================
sent_from = gmail_user
sent_to = ['[email protected]', '[email protected]']
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)

Portanto, se você tiver sucesso, verá uma imagem como esta:

Testei enviando um e-mail de e para mim.

E-mail enviado com sucesso.

Nota: tenho a verificação em duas etapas ativada na minha conta. Senha do aplicativo funciona com isso! (para a configuração do gmail smtp, você deve acessar https://support.google.com/accounts/answer/185833?hl=pt-BR e seguir as etapas abaixo)

Essa configuração não está disponível para contas com a verificação em duas etapas ativada. Essas contas exigem uma senha específica do aplicativo para acesso a aplicativos menos seguro.

Acesso menos seguro ao aplicativo ... Essa configuração não está disponível para contas com a verificação em duas etapas ativada.

JayRizzo
fonte
1
Solução fantástica e muito bem explicada no código. Obrigado Jay, muito apreciado. Pergunta idiota: você sabe qual é o limite máximo de e-mails por dia que pode ser enviado (com o Gmail)?
Angelo
Obrigado @Angelo, mas sim, há um limite, GMail = 500 e-mails ou 500 destinatários / dia ref: support.google.com/mail/answer/22839 G SUITE é diferente e tem 2000 mensagens / dia e pode ser encontrado aqui: support .google.com / a / answer / 166852 Boa sorte!
precisa saber é o seguinte
2
Todas as outras são postagens mais antigas e podem não estar funcionando, mas isso é 100% funcionando. Gere senhas de aplicativos. Obrigado pela resposta
Shubh
1
Estou um pouco surpreso que esta solução não tenha mais votos positivos. Eu não tentei todos os outros, mas tentei vários, e apenas este funcionou fora da caixa, com 0 ajustes.
mcouthon 15/04
14

Você pode encontrá-lo aqui: 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())
Froyo
fonte
2
mais 1 porque é melhor criar um MIME do que codificar sua própria cadeia de caracteres de formato. O MIMEMultipart é necessário para uma simples mensagem de texto? Ou o seguinte também está correto: stackoverflow.com/a/6270987/895245
Ciro Santilli #: 22215
Onde você instancia a variável de email?
madcat
11

Não está diretamente relacionado, mas ainda vale a pena destacar é que meu pacote tenta tornar o envio de mensagens do Gmail muito rápido e indolor. Ele também tenta manter uma lista de erros e tenta apontar para a solução imediatamente.

Literalmente, seria necessário apenas esse código para fazer exatamente o que você escreveu:

import yagmail
yag = yagmail.SMTP('[email protected]')
yag.send('[email protected]', 'Why,Oh why!')

Ou um forro:

yagmail.SMTP('[email protected]').send('[email protected]', 'Why,Oh why!')

Para o pacote / instalação, consulte git ou pip , disponível para Python 2 e 3.

PascalVKooten
fonte
9

Aqui está um exemplo da API do Gmail. Embora seja mais complicado, esse é o único método que achei que funciona em 2019. Este exemplo foi obtido e modificado em:

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

Você precisará criar um projeto com as interfaces de API do Google por meio do site deles. Em seguida, você precisará ativar a API do GMAIL para seu aplicativo. Crie credenciais e faça o download desses creds, salve-o como 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("[email protected]", "[email protected]", "Subject", "Msg")
    send_message( service, 'me', msg)

if __name__ == '__main__':
    main()
Luke Dupin
fonte
O smtplib não é totalmente seguro para threads, por isso terá problemas ao enviar mensagens simultâneas. Essa é a abordagem correta.
dsbajna 18/03
2

Agora existe uma API do gmail, que permite enviar e-mail, ler e criar rascunhos via REST. Diferentemente das chamadas SMTP, é sem bloqueio, o que pode ser uma boa coisa para servidores da Web baseados em encadeamento que enviam email no encadeamento de solicitação (como servidores da web python). A API também é bastante poderosa.

  • Obviamente, o email deve ser enviado para uma fila que não seja servidor da Web, mas é bom ter opções.

É mais fácil de configurar se você tiver direitos de administrador do Google Apps no domínio, pois poderá conceder permissão geral ao seu cliente. Caso contrário, você precisará mexer na autenticação e permissão do OAuth.

Aqui está uma essência demonstrando:

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

Tim Richardson
fonte
2

ótima resposta do @David, aqui está o Python 3 sem a tentativa genérica, exceto:

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()
Juan Isaza
fonte
2

Ative aplicativos menos seguros na sua conta do Gmail e use (Python> = 3.6):

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

gmailUser = '[email protected]'
gmailPassword = 'XXXXX'
recipient = '[email protected]'

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...')
CONvid19
fonte
1
Resposta realmente fantástica. Melhor do grupo, super conciso. Obrigado.
Bruce Dean
Obrigado Pedro, sua resposta resolveu. Btw para quem usa o Gsuite com vários aliases; basta adicionar o alias à sua conta do gmail seguindo support.google.com/mail/answer/22370?hl=en e você pode enviar usando o alias substituindo <{gmailUser}>por <YourAlias>.
LucSpan 30/03
1

Parece problema do antigo smtplib. Nopython2.7 tudo funciona bem.

Atualização : Sim, server.ehlo()também poderia ajudar.

mega.venik
fonte
-1
    import smtplib

    fromadd='[email protected]'
    toadd='[email protected]'

    msg='''hi,how r u'''
    username='[email protected]'
    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
Shyam Gupta
fonte
Estou postando o código simples que fará como enviar e-mails da conta do Gmail. Se você precisar de alguma informação, entre em contato. Espero que o código ajude a todos os usuários.
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()
Sam Divya Kumar
fonte
código simples para enviar um email pelo gmail usando código python. do endereço é seu gmailID e o endereço do destinatário é o ID do e-mail que você envia.
Sam Divya Kumar