Як надіслати електронний лист з Gmail як постачальника за допомогою Python?


289

Я намагаюся надсилати електронну пошту (Gmail) за допомогою python, але отримую наступну помилку.

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.

Сценарій Python такий.

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
Це питання слід розблокувати зараз, коли Google рухається до внутрішнього API для надсилання повідомлень через gmail. Цей крок робить застарілими всі, крім однієї з цих відповідей, і одна відповідна відповідь дуже легка для фактичного вирішення проблеми.
Андрій

Також для користувачів VPN, якщо проблема все ще зберігається, вимкніть VPN. Це працювало для мене.
Павло

Відповіді:


211

Вам потрібно сказати, EHLOперш ніж просто запустити STARTTLS:

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

Крім того, ви дійсно повинні створити From:, To:і Subject:заголовки повідомлень, відокремлений від тіла повідомлення символом нового рядка і використання в CRLFякості маркерів EOL.

Напр

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

2
виклик server.sendmail (fromaddr, toaddrs, msg) другий параметр, toaddrs повинен бути списком, toaddrs = ['user_me@gmail.com']
Массімо Фаццоларі

14
Станом на серпень 2014 року, тепер підвищується smtplib.SMTPAuthenticationError: (534, '
5.7.9

7
Для мене мені довелося включити пароль програми для входу за допомогою облікового запису @google, щоб надсилати електронні листи через python: support.google.com/accounts/answer/…
anon58192932

1
Ось посилання на як відправити кілька людей: stackoverflow.com/questions/8856117 / ...
anon58192932

1
Одного разу я ввійшов на SMTP-сервер по telnet і надіслав EHLOдрукарською помилкою. Після того як я спробував HELO багато разів, але реакція була іншою. Минули години, щоб зрозуміти, що EHLO - це команда, яку SMTP розуміє, і я написав помилку.
Шиплу Мокаддім

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"

якщо ви хочете використовувати порт 465, вам потрібно створити SMTP_SSLоб'єкт:

# 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
Дуже приємний зразок дякую. Я думаю, що я помітив, що якщо я хочу використовувати SSL-з'єднання, мені довелося видалити server.starttls ()
Dowlers

18
Чи не працює більше , до жаль: smtplib.SMTPAuthenticationError: (534, «5.7.14 < accounts.google.com / ... ... Будь ласка , увійдіть через веб - браузер і \ n5.7.14 спробуйте ще раз \ n5.7.14 ЖЖ. докладніше за адресою \ n5.7.14 support.google.com/mail/bin/answer.py?answer=78754 ... Тоді я отримав повідомлення від Google, що сталася підозріла спроба з'єднання.
royskatt

13
@royskatt - все, що вам потрібно зробити, це створити пароль програми та використовувати його замість пароля вашого облікового запису. Створіть тут пароль програми: security.google.com/settings/security/apppasswords
Джаред

15
@royskatt: Я щойно вирішив проблему, з якою ви стикаєтесь. У Google є налаштування, щоб дозволити доступ до менш захищених додатків, просто потрібно увімкнути його "Увімкнено". ви можете потрапити туди: Google -> мій обліковий запис -> Вхід та безпека -> Підключені програми та сайти -> прокрутіть униз, і ви знайдете "Дозволити менш захищені програми"
shaleen mohan

2
Якщо ваша електронна адреса захищена двофакторною автентифікацією, спершу потрібно створити специфічний пароль програми -> а потім скористатися цим паролем програми для наведеного вище коду прикладу (це дуже важливо, оскільки тоді ви не записуєте свій пароль ніде у чіткому тексті І ви можете будь-коли відкликати пароль програми).
Тревор Бойд Сміт

136

Я зіткнувся з подібною проблемою і натрапив на це питання. Я отримав помилку автентифікації SMTP, але моє ім’я / пароль користувача було правильним. Ось що це зафіксувало. Я читав це:

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

Коротше кажучи, google не дозволяє входити через smtplib, оскільки він позначив такий тип входу як "менш безпечний", тому що вам потрібно зробити, це перейти до цього посилання під час входу в обліковий запис google, і дозволити доступ:

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

Після того, як це встановлено (див. Мій скріншот нижче), воно повинно працювати.

введіть тут опис зображення

Зараз вхід працює:

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

Відповідь після зміни:

(235, '2.7.0 Accepted')

Попередній відповідь:

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

Ще не працює? Якщо ви все ще отримуєте SMTPAuthenticationError, але тепер код 534, його немає, оскільки місцезнаходження невідоме. Перейдіть за цим посиланням:

https://accounts.google.com/DisplayUnlockCaptcha

Натисніть кнопку "Продовжити", і це повинно дати вам 10 хвилин для реєстрації нового додатка. Тож приступайте до ще однієї спроби входу, і це має спрацювати.

ОНОВЛЕННЯ : Це, здається, не працює відразу, ви можете затриматись на деякий час, отримуючи цю помилку в smptlib:

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

У повідомленні йдеться про використання браузера для входу:

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

Після ввімкнення 'lesssecureapps' зайдіть на каву, поверніться та спробуйте посилання "DisplayUnlockCaptcha" ще раз. Згідно з досвідом користувача, для початку зміни може знадобитися до години. Потім спробуйте ввійти ще раз.


3
ТАК ДЯКУЮ ! Сталося під час використання фляш-пошти
Джанніс

1
спасибі людині проблема тільки для мене: accounts.google.com/DisplayUnlockCaptcha
Limitless іша

6
Крім того, залиште півгодини на годину, щоб змінити налаштування. Я створив новий обліковий запис, відключив всю додану безпеку і все-таки отримав ту саму помилку. Приблизно через годину це все спрацювало.
jkgeyti

2
Увімкнення менш захищених додатків неможливо, якщо у вас активована "двоетапна перевірка". Найкращий і найбезпечніший варіант - увімкнути "apppassword" security.google.com/settings/security/apppasswords, як уже було запропоновано, і він працює як чарівність
Omiod

2
Коли я переходжу посилання apppasswords, усі мої облікові записи Google отримують помилку "Налаштування, яку ви шукаєте, недоступно для вашого облікового запису".
Сюзанна

18

Ви вниз з 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
Якщо у вашому класі є лише два методи, один з яких - __init__, просто використовуйте функцію.
JoeQuery

Як би ви додали додаток за допомогою цього методу?
sgerbhctim

Використання класу було б добре, якби ви хотіли закликати клієнта і передати його іншим частинам коду, а не передавати електронну пошту та пароль. Або якщо ви хочете надіслати кілька повідомлень, не вводячи електронний лист та пароль кожен раз.
Самі Старт

15

Це працює

Створіть пароль додатка Gmail!

Після створення цього створіть файл з назвою sendgmail.py

Потім додайте цей код :

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

Отже, якщо ви досягли успіху, ви побачите таке зображення:

Я перевіряв, надсилаючи електронний лист від себе та до себе.

Успішно надіслано електронний лист.

Примітка. У моєму акаунті увімкнено двоетапну перевірку . Пароль пароля додатків працює з цим! (для налаштування smtp для gmail потрібно перейти на сторінку https://support.google.com/accounts/answer/185833?hl=uk та виконати наведені нижче дії)

Цей параметр недоступний для облікових записів із увімкненою двоетапною підтвердженням. Для таких облікових записів потрібен специфічний пароль для менш безпечного доступу до додатків.

Менш безпечний доступ до додатків ... Цей параметр недоступний для облікових записів із увімкненою двоетапною підтвердженням.


1
Фантастичне рішення і дуже добре пояснено в коді. Дякую, Джей, дуже вдячний. Дурне запитання: чи знаєте ви, яка максимальна межа електронних листів на день може бути надіслана (з gmail)?
Анджело

Дякую @Angelo, але так, є обмеження, GMail = 500 електронних листів або 500 одержувачів / Денна посилання: support.google.com/mail/answer/22839 G SUITE відрізняється і складає 2000 повідомлень на день, і їх можна знайти тут: підтримка .google.com / a / відповідь / 166852 удачі!
JayRizzo

2
Усі інші є старшими посадами і, можливо, не працюють, але це на 100% працює. Створюйте паролі додатків. Дякую за відповідь
Шуб

1
Я трохи здивований, що це рішення не має більшої кількості результатів. Я не пробував усіх інших, але я спробував декілька, і тільки цей вийшов з коробки, з 0 майстерністю.
mcouthon

14

Ви можете знайти його тут: 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
плюс 1, тому що краще побудувати MIME, ніж жорсткий код власного рядка формату. Чи потрібен MIMEMultipart для простого текстового повідомлення? Або наступний теж правильно: stackoverflow.com/a/6270987/895245
Чіро Сантіллі郝海东冠状病六四事件法轮功

Де ти інстанціюєш змінну електронної пошти?
madcat

11

Не пов’язане безпосередньо, але все ж варто зазначити, що мій пакет намагається зробити відправлення Gmail-повідомлень справді швидким і безболісним. Він також намагається підтримувати список помилок і намагається негайно вказати на рішення.

Буде буквально потрібен лише цей код, щоб зробити саме те, що ви написали:

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

Або один вкладиш:

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

Про пакет / установку, будь ласка, подивіться на git або pip , доступні як для Python 2, так і для 3.


9

Ось приклад API Gmail. Хоча це складніше, це єдиний метод, який я виявив, що працює у 2019 році. Цей приклад взяли та модифікували з:

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

Вам потрібно створити проект з інтерфейсами API Google через їх веб-сайт. Далі потрібно активувати API GMAIL для свого додатка. Створіть облікові дані, а потім завантажте ці записи, збережіть їх як 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("from@gmail.com", "to@gmail.com", "Subject", "Msg")
    send_message( service, 'me', msg)

if __name__ == '__main__':
    main()

smtplib не є повністю безпечним для потоків, тому у нього виникнуть проблеми з надсиланням одночасних повідомлень. Це правильний підхід.
dsbajna

2

Зараз існує gmail API, який дозволяє надсилати електронну пошту, читати електронну пошту та створювати чернетки через REST. На відміну від SMTP-дзвінків, саме блокування може бути хорошою справою для потокових веб-серверів, що надсилають електронну пошту в потоці запиту (наприклад, веб-серверів python). API також досить потужний.

  • Звичайно, електронну пошту потрібно передавати в чергу, що не належить веб-серверам, але приємно мати варіанти.

Найпростіше налаштувати, якщо у вас є права адміністратора Google Apps на домен, оскільки тоді ви можете надати клієнту дозвіл на покриття. Інакше вам доведеться поспілкуватися з автентифікацією та дозволом OAuth.

Ось суть, яка це демонструє:

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


2

чудова відповідь від @David, ось для Python 3 без загальної спроби, крім:

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

Увімкніть менш захищені програми у своєму акаунті gmail та використовуйте (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
Дійсно фантастична відповідь. Найкращий з букетів, супер лаконічний. Дякую.
Брюс Дін

Дякую Педро, ваша відповідь вирішила це. Btw для всіх, хто використовує Gsuite з кількома псевдонімами; просто додайте псевдонім у свій обліковий запис gmail, дотримуючись support.google.com/mail/answer/22370?hl=uk, і ви можете надіслати його, замінивши <{gmailUser}>на <YourAlias>.
LucSpan

1

Схоже, проблема старої smtplib. У python2.7всьому добре працює.

Оновлення : Так, server.ehlo()також може допомогти.


-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

Я публікую простий код, який допоможе надіслати пошту з облікового запису Gmail. Якщо вам потрібна будь-яка інформація, то дайте мені знати. Сподіваюся, що код допоможе всім користувачам.
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()

простий код для відправки пошти через gmail за допомогою python-коду. з адреси - ваш gmailID, а адреса адреси - це ідентифікатор пошти, на який ви надсилаєте пошту.
Сем Дівія Кумар
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.