Как отправить письмо с 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']
Massimo Fazzolari

14
По состоянию на август 2014 г. теперь возникает smtplib.SMTPAuthenticationError: (534, '5.7.9 Требуется пароль для конкретного приложения.
anon58192932

7
Мне, однако, пришлось включить пароль «app» для входа в систему с помощью учетной записи @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 Learn подробнее на \ 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
ДА СПАСИБО ! Произошло это при использовании флеш-почты
Giannis

1
Спасибо, проблема только для меня: account.google.com/DisplayUnlockCaptcha
Безлимитный isa

6
Кроме того, пожалуйста, оставьте от получаса до часа для изменения настроек. Я создал новую учетную запись, отключил все дополнительные средства безопасности и все еще получил ту же ошибку. Примерно через час все заработало.
Jkgeyti

2
Включение менее защищенных приложений невозможно, если у вас включена «Двухэтапная проверка». Лучший и самый безопасный вариант - включить «apppassword» security.google.com/settings/security/apppasswords, как уже предлагалось, и он работает как
чудо

2
Когда я перехожу по ссылке apppasswords, все мои учетные записи Google получают ошибку «Настройка, которую вы ищете, недоступна для вашей учетной записи».
Сюзанна

18

Вы с ООП?

#!/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=ru и выполнить следующие действия)

Этот параметр недоступен для учетных записей с включенной двухэтапной проверкой. Такие учетные записи требуют пароль конкретного приложения для менее безопасного доступа к приложениям.

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


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

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

2
Все остальные посты старше и могут не работать, но это на 100% работает. Создайте пароли приложения. Спасибо за ответ
Shubh

1
Я немного удивлен, что это решение не имеет больше голосов. Я не пробовал все остальные, но я пробовал несколько, и только этот работал из коробки, с нулями.
Макутон

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

Вот пример Gmail API. Хотя это более сложный метод, это единственный метод, который я обнаружил в 2019 году. Этот пример был взят и изменен из:

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

Вам нужно будет создать проект с интерфейсами API Google через их веб-сайт. Затем вам нужно включить GMAIL API для вашего приложения. Создайте учетные данные, а затем загрузите эти кредиты, сохраните их как 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 не является полностью потокобезопасным, поэтому у него будут проблемы с отправкой параллельных сообщений. Это правильный подход.
Дсбаджна

2

Теперь есть API Gmail, который позволяет отправлять электронную почту, читать электронную почту и создавать черновики через REST. В отличие от вызовов SMTP, это неблокирование, что может быть полезно для потоковых веб-серверов, отправляющих электронную почту в потоке запросов (например, веб-серверы Python). API также довольно мощный.

  • Конечно, электронная почта должна передаваться в очередь без веб-сервера, но приятно иметь варианты.

Настроить проще всего, если у вас есть права администратора Служб Google в домене, потому что тогда вы можете дать полное разрешение своему клиенту. В противном случае вам придется использовать аутентификацию и разрешение OAuth.

Вот суть, демонстрирующая это:

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


2

отличный ответ от @David, здесь для Python 3 без общего try-кроме:

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
Действительно фантастический ответ. Лучший из множества, супер лаконичен. Спасибо.
Брюс Дин

Спасибо Педро, твой ответ решил это. Кстати, для тех, кто использует Gsuite с несколькими псевдонимами; просто добавьте псевдоним в свой аккаунт Gmail, выполнив support.google.com/mail/answer/22370?hl=ru, и вы можете отправить его с помощью псевдонима, заменив его <{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. Если вам нужна информация, дайте мне знать. Я надеюсь, что код поможет всем пользователям.
Шьям Гупта

-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. from address - это ваш gmailID, а receiveraddress - это почтовый идентификатор, на который вы отправляете почту.
Сам Дивья Кумар
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.