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 = '[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
źródło
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: [email protected]",
  "To: [email protected]",
  "Subject: Just a message",
  "",
  "Why, oh why"
  ])
MattH
źródło
2
wywoływanie server.sendmail (fromaddr, toaddrs, msg) drugi parametr, toaddrs musi być listą, toaddrs = ['[email protected]']
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'
David Okwii
źródło
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('[email protected]', '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ć.

radtek
źródło
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')
Ricky Wilson
źródło
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 = '[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)

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ą.

JayRizzo
źródło
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())
Froyo
źródło
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('[email protected]')
yag.send('[email protected]', 'Why,Oh why!')

Lub jedna wkładka:

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

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

PascalVKooten
źródło
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("[email protected]", "[email protected]", "Subject", "Msg")
    send_message( service, 'me', msg)

if __name__ == '__main__':
    main()
Luke Dupin
źródło
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

Tim Richardson
źródło
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()
juan Isaza
źródło
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 = '[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
źródło
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.

mega.venik
źródło
-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
źródło
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()
Sam Divya Kumar
źródło
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,