Jak wysłać wiadomość e-mail z Gmailem jako dostawcą za pomocą Pythona?


289

Próbuję wysłać wiadomość e-mail (Gmail) za pomocą języka Python, ale otrzymuję następujący błąd.

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.

Skrypt w języku Python jest następujący.

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
To pytanie powinno zostać odblokowane teraz, gdy Google zmierza w kierunku wewnętrznego interfejsu API do wysyłania wiadomości za pośrednictwem Gmaila. Ten krok powoduje, że wszystkie odpowiedzi z wyjątkiem jednej są nieaktualne, a jedna istotna odpowiedź jest bardzo lekka na faktyczne rozwiązanie problemu.
Andrew

Ponadto dla użytkowników VPN, jeśli problem nadal występuje, wyłącz VPN. To działało dla mnie.
Paul

Odpowiedzi:


211

Musisz powiedzieć, EHLOzanim wpadniesz prosto na STARTTLS:

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

Ponadto należy stworzyć naprawdę From:, To:a Subject:nagłówki wiadomości, oddzielone od treści wiadomości przez pustą linię i użycia CRLFjako znaczniki EOL.

Na przykład

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

2
wywoływanie server.sendmail (fromaddr, toaddrs, msg) drugi parametr, toaddrs musi być listą, toaddrs = ['user_me@gmail.com']
Massimo Fazzolari 20.08.2013

14
Od sierpnia 2014 r. Powoduje to teraz błąd smtplib.SMTPAuthenticationError: (534, „5.7.9 Wymagane hasło specyficzne dla aplikacji.
anon58192932,

7
Dla mnie jednak musiałem włączyć hasło „aplikacji”, aby zalogować się przy użyciu konta @google, aby wysyłać e-maile przez python: support.google.com/accounts/answer/…
anon58192932

1
Oto link do wysyłania wielu osób: stackoverflow.com/questions/8856117/…
anon58192932

1
Raz zalogowałem się na serwerze SMTP przez telnet i wysłałem EHLOliterówkę. Po tym, jak wiele razy próbowałem HELO, ale odpowiedź była inna. Wiele godzin zajęło ustalenie, że EHLO jest tak naprawdę poleceniem zrozumiałym dla SMTP i zrobiłem literówkę.
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"

jeśli chcesz użyć portu 465, musisz utworzyć SMTP_SSLobiekt:

# 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
Bardzo ładna próbka dzięki. Zauważyłem jedną myśl, że jeśli chcę użyć połączenia SSL, musiałem usunąć server.starttls ()
Dowlers

18
Niestety już nie działa: smtplib.SMTPAuthenticationError: (534, „5.7.14 < accounts.google.com/… ... Zaloguj się za pomocą przeglądarki internetowej i \ n5.7.14, a następnie spróbuj ponownie. \ N5.7.14 Dowiedz się więcej na \ n5.7.14 support.google.com/mail/bin/answer.py?answer=78754 ... Potem dostałem wiadomość od Google, że podejrzewa się podejrzaną próbę połączenia.
royskatt

13
@royskatt - wszystko, co musisz zrobić, to utworzyć hasło do aplikacji i używać go zamiast hasła do konta. Utwórz hasło do aplikacji tutaj: security.google.com/settings/security/apppasswords
Jared

15
@royskatt: Właśnie rozwiązałem problem, z którym się zmierzyłeś. Google ma ustawienie umożliwiające dostęp do mniej bezpiecznych aplikacji, wystarczy je włączyć. możesz się tam dostać z: Google -> moje konto -> Logowanie i bezpieczeństwo -> Połączone aplikacje i witryny -> przewiń w dół, a znajdziesz „Zezwalaj na mniej bezpieczne aplikacje”
shaleen mohan

2
Jeśli Twój Gmail jest zabezpieczony przez uwierzytelnianie dwuskładnikowe, musisz najpierw wygenerować hasło aplikacji -> następnie użyć tego hasła do aplikacji w powyższym przykładowym kodzie (jest to bardzo ważne, ponieważ nigdzie nie zapisujesz swojego hasła jawnym tekstem ORAZ w każdej chwili możesz odwołać hasło do aplikacji).
Trevor Boyd Smith

136

Wpadłem na podobny problem i natknąłem się na to pytanie. Wystąpił błąd uwierzytelnienia SMTP, ale moja nazwa użytkownika / hasło było prawidłowe. Oto, co to naprawiło. Przeczytałem to:

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

Krótko mówiąc, Google nie zezwala na logowanie się za pomocą smtplib, ponieważ oznaczało ten rodzaj logowania jako „mniej bezpieczny”, więc musisz przejść do tego linku, gdy jesteś zalogowany na swoje konto Google, i zezwól na dostęp:

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

Po ustawieniu (patrz mój zrzut ekranu poniżej), powinno działać.

wprowadź opis zdjęcia tutaj

Zaloguj się teraz działa:

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

Odpowiedź po zmianie:

(235, '2.7.0 Accepted')

Odpowiedź wcześniej:

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

Wciąż nie działa? Jeśli nadal pojawia się błąd SMTPAuthenticationError, ale teraz kod to 534, to dlatego, że lokalizacja jest nieznana. Śledź ten link:

https://accounts.google.com/DisplayUnlockCaptcha

Kliknij Kontynuuj, co powinno dać 10 minut na zarejestrowanie nowej aplikacji. Przejdź teraz do kolejnej próby logowania i powinno to działać.

AKTUALIZACJA : Wydaje się, że to nie działa od razu, możesz utknąć na chwilę, otrzymując ten błąd w smptlib:

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

Komunikat mówi, aby zalogować się za pomocą przeglądarki:

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

Po włączeniu „lesssecureapps” idź na kawę, wróć i ponownie spróbuj użyć linku „DisplayUnlockCaptcha”. Z doświadczenia użytkownika może upłynąć nawet godzina, zanim zmiana zostanie wprowadzona. Następnie spróbuj ponownie się zalogować.


3
TAK DZIĘKUJĘ ! Zdarzyło się podczas korzystania z poczty kolby
Giannis

1
dzięki, stary, problem tylko dla mnie: accounts.google.com/DisplayUnlockCaptcha
Nieograniczona isa

6
Ponadto należy odczekać od pół godziny do godziny na zmianę ustawień. Utworzyłem nowe konto, wyłączyłem wszystkie dodane zabezpieczenia i nadal otrzymałem ten sam błąd. Około godziny później wszystko działało.
jkgeyti

2
Włączanie mniej bezpiecznych aplikacji nie jest możliwe, jeśli masz włączoną funkcję „weryfikacji dwuetapowej”. Najlepszą i najbezpieczniejszą opcją jest włączenie „apppassword” security.google.com/settings/security/apppasswords, jak już sugerowano, i działa jak urok
Omiod

2
Gdy podążam za linkiem do hasła aplikacji, na wszystkich moich kontach Google pojawia się komunikat „Szukane ustawienie nie jest dostępne dla Twojego konta”.
Suzanne

18

Nie rozumiesz 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
Jeśli twoja klasa ma tylko dwie metody, z których jedną jest __init__, po prostu użyj funkcji.
JoeQuery

Jak dodasz załącznik przy użyciu tej metody?
sgerbhctim

Użycie klasy byłoby dobre, gdybyś chciał zainicjować klienta i przekazać go innym częściom kodu, zamiast przekazywać adres e-mail i hasło. Lub jeśli chcesz wysłać kilka wiadomości bez podawania adresu e-mail i hasła za każdym razem.
Sami Start

15

To działa

Utwórz hasło do aplikacji Gmail!

Po utworzeniu pliku utwórz plik o nazwie sendgmail.py

Następnie dodaj ten kod :

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

Jeśli więc ci się powiedzie, zobaczysz taki obraz:

Przetestowałem, wysyłając wiadomość e-mail zi do siebie.

Wysłano pomyślnie wiadomość e-mail.

Uwaga: na moim koncie jest włączona weryfikacja dwuetapowa . Hasło aplikacji działa z tym! (w celu skonfigurowania Gmaila smtp należy przejść do https://support.google.com/accounts/answer/185833?hl=pl i wykonać poniższe kroki)

To ustawienie nie jest dostępne dla kont z włączoną weryfikacją dwuetapową. Takie konta wymagają hasła aplikacji, aby uzyskać mniej bezpieczny dostęp do aplikacji.

Mniej bezpieczny dostęp do aplikacji ... To ustawienie nie jest dostępne dla kont z włączoną weryfikacją dwuetapową.


1
Fantastyczne rozwiązanie i bardzo dobrze wyjaśnione w kodzie. Dziękuję Jay, bardzo doceniony. Głupie pytanie: czy wiesz, jaki jest maksymalny limit liczby wiadomości e-mail dziennie (za pomocą Gmaila)?
Angelo

Dziękuję @Angelo, ale tak, istnieje limit, Gmail = 500 e-maili lub 500 adresatów / Dzień ref: support.google.com/mail/answer/22839 G SUITE jest inny i ma 2000 wiadomości dziennie i można go znaleźć tutaj: wsparcie .google.com / a / answer / 166852 Powodzenia!
JayRizzo

2
Wszystkie pozostałe są starszymi postami i mogą nie działać, ale to działa w 100%. Wygeneruj hasła do aplikacji. Dzięki za odpowiedź
Shubh

1
Jestem trochę zaskoczony, że to rozwiązanie nie ma więcej pozytywnych opinii. Nie wypróbowałem wszystkich pozostałych, ale próbowałem kilku, i tylko ten wyszedł z pudełka, z 0 majsterkowania.
mcouthon

14

Można go znaleźć tutaj: 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, ponieważ lepiej zbudować MIME niż zakodować własny ciąg formatu. Czy MIMEMultipart jest wymagany do prostej wiadomości tekstowej? Lub jest również poprawny: stackoverflow.com/a/6270987/895245
Ciro Santilli 22 冠状 病 六四 事件 法轮功

Gdzie tworzysz zmienną e-mail?
madcat

11

Nie ma bezpośredniego związku, ale nadal warto podkreślić, że moja paczka próbuje sprawić, by wysyłanie wiadomości Gmail było naprawdę szybkie i bezbolesne. Próbuje także utrzymywać listę błędów i natychmiast wskazuje rozwiązanie.

Dosłownie wystarczyłby ten kod, aby zrobić dokładnie to, co napisałeś:

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

Lub jedna wkładka:

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

Pakiet / instalację można znaleźć na git lub pip , dostępnym zarówno dla Pythona 2, jak i 3.


9

Oto przykład interfejsu API Gmaila. Chociaż jest to bardziej skomplikowane, jest to jedyna metoda, którą znalazłem, która działa w 2019 roku. Ten przykład został wzięty i zmodyfikowany z:

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

Musisz stworzyć projekt z interfejsami API Google za pośrednictwem ich strony internetowej. Następnie musisz włączyć interfejs API GMAIL dla swojej aplikacji. Utwórz poświadczenia, a następnie pobierz je, zapisz jako poświadczenia. 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 nie jest w pełni bezpieczny dla wątków, więc będzie miał problemy z wysyłaniem równoczesnych wiadomości. To jest właściwe podejście.
dsbajna

2

Obecnie dostępny jest interfejs API Gmaila, który umożliwia wysyłanie wiadomości e-mail, czytanie wiadomości e-mail i tworzenie wersji roboczych za pośrednictwem usługi REST. W przeciwieństwie do wywołań SMTP, nie blokuje, co może być dobrą rzeczą dla serwerów opartych na wątkach wysyłających wiadomości e-mail w wątku żądania (np. Serwery python). Interfejs API jest również dość wydajny.

  • Oczywiście wiadomość e-mail należy przekazywać do kolejki innej niż serwer WWW, ale fajnie jest mieć opcje.

Najłatwiej jest skonfigurować, jeśli masz uprawnienia administratora Google Apps w domenie, ponieważ wtedy możesz udzielić klientowi ogólnych uprawnień. W przeciwnym razie musisz majstrować przy uwierzytelnianiu i autoryzacji OAuth.

Oto jego istota:

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


2

świetna odpowiedź od @David, tutaj jest dla Python 3 bez ogólnego try-wyjątkiem:

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

Włącz mniej bezpieczne aplikacje na swoim koncie Gmail i użyj (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
Naprawdę fantastyczna odpowiedź. Najlepszy ze wszystkich, super zwięzły. Dziękuję Ci.
Bruce Dean

Dzięki Pedro, twoja odpowiedź rozwiązała ten problem. Btw dla każdego używającego Gsuite z wieloma aliasami; po prostu dodaj alias do swojego konta Gmail zgodnie z support.google.com/mail/answer/22370?hl=pl, a możesz wysyłać za pomocą aliasu, zastępując <{gmailUser}>go <YourAlias>.
LucSpan

1

Wydaje się, że to problem starego smtplib. We python2.7wszystkim działa dobrze.

Aktualizacja : Tak, server.ehlo()również może pomóc.


-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

Publikuję prosty kod, który zrobi, jak wysyłać pocztę z konta Gmail. Jeśli potrzebujesz jakichkolwiek informacji, daj mi znać. Mam nadzieję, że ten kod pomoże wszystkim użytkownikom.
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()

prosty kod do wysłania poczty przez Gmaila za pomocą kodu Pythona. z adresu jest twój gmailID, a adres odbiorcy to identyfikator poczty, którą wysyłasz.
Sam Divya Kumar,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.