Отправить почту в Gmail с python - PullRequest
2 голосов
/ 01 апреля 2020

Я пытаюсь отправить простое тестовое электронное письмо с помощью API Gmail, но продолжаю получать одну и ту же ошибку для каждого примера кода, который я нахожу.

В настоящий момент мой код такой:

def validationService():
    SCOPES = ['https://mail.google.com/']
    SERVICE_ACCOUNT_FILE = 'creds.json'
    creds = service_account.Credentials.from_service_account_file(SERVICE_ACCOUNT_FILE, scopes=SCOPES)

    service = build('gmail', 'v1', credentials=creds)
    return service


def SendMessage(service, user_id, message):
  try:
    message = (service.users().messages().send(userId=user_id, body=message).execute())
    print('Message Id:',message['id'])
    return message
  except errors.HttpError as error:
    print('An error occurred:', error)


def CreateMessage(sender, to, subject, message_text):
  message = MIMEText(message_text)
  message['to'] = to
  message['from'] = sender
  message['subject'] = subject
  return {'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode()}

service = validationService()

email = CreateMessage("sendermail@gmail.com", "receiverrmail@gmail.com", "Test", "This is a test")

sent = SendMessage(service, "sendermail@gmail.com", email)

Возвращает

>>> An error occurred: <HttpError 400 when requesting https://www.googleapis.com/gmail/v1/users/me/messages/send?alt=json returned "Bad Request">

Я также не понимаю разницы между параметром "отправитель" в CreateMessage и userId в SendMessage.

Если я использую цель, я использую учетные данные учетной записи службы

- Спасибо!

Ответы [ 2 ]

2 голосов
/ 01 апреля 2020

При использовании учетной записи службы с Gmail API . Вам необходимо установить делегирование по всему домену , которое позволяет учетной записи службы выдавать себя за любого пользователя в вашем G Suite домене . Следовательно, вы должны иметь учетную запись G Suite, чтобы иметь возможность использовать широкое делегирование домена, как говорят документы:

Если у вас есть домен G Suite, например, если вы используете G Suite, Администратор домена G Suite может авторизовать приложение для доступа к пользовательским данным от имени пользователей в домене G Suite.

Итак, зачем вам выдавать себя за пользователя (реального человека)? это связано с тем, что служебная учетная запись - это бот (а не реальный человек), который используется для взаимодействия между серверами, благодаря чему ваше приложение вызывает API-интерфейсы Google, и хотя учетная запись службы имеет параметр client_email, который имеет структура, подобная name@project-randomnumber.iam.gserviceaccount.com, это не реальная электронная почта, которая принадлежит реальному человеку (я знаю, что это немного сбивает с толку).

Сказав это, я внес некоторые изменения в ваш код. Во-первых, я изменил вашу функцию validationService, чтобы создать службу с использованием делегирования на уровне домена.

def validationService():
    # Set the crendentials 
    credentials = service_account.Credentials.\
        from_service_account_file(SERVICE_ACCOUNT_FILE, scopes= SCOPES)
    # Delegate the credentials to the user you want to impersonate
    delegated_credentials = credentials.with_subject(USER_EMAIL)
    service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
    return service

В вашей функции SendMessage необязательно передавать пользователя, который собирается отправлять электронную почту. , Использование me достаточно в качестве Users.messages: send Параметры состояние:

userId string Адрес электронной почты пользователя. Специальное значение me может использоваться для обозначения аутентифицированного пользователя.

def SendMessage(service, message):
    message = service.users().messages().send(userId="me", body=message).execute()
    return message

Весь код в конце может выглядеть так:

from googleapiclient import discovery, errors
from oauth2client import file, client, tools
from google.oauth2 import service_account
from email.mime.text import MIMEText
import base64

SERVICE_ACCOUNT_FILE = 'service_account.json'
SCOPES = [' https://mail.google.com/']
# The user we want to "impersonate"
USER_EMAIL = "user@domain"


def validationService():
    # Set the crendentials 
    credentials = service_account.Credentials.\
        from_service_account_file(SERVICE_ACCOUNT_FILE, scopes= SCOPES)
    # Delegate the credentials to the user you want to impersonate
    delegated_credentials = credentials.with_subject(USER_EMAIL)
    service = discovery.build('gmail', 'v1', credentials=delegated_credentials)
    return service


def SendMessage(service, message):
    message = service.users().messages().send(userId="me", body=message).execute()
    return message


def CreateMessage(sender, to, subject, message_text):
  message = MIMEText(message_text)
  message['to'] = to
  message['from'] = sender
  message['subject'] = subject
  return {'raw': base64.urlsafe_b64encode(message.as_string().encode()).decode()}


def main():
    try:
        service = validationService()
        email = CreateMessage(USER_EMAIL, "receiverrmail@domain", "Test", "This is a test")
        email_sent = SendMessage(service, email)
        print('Message Id:', email_sent['id'])
    except errors.HttpError as err:
        print('\n---------------You have the following error-------------')
        print(err)
        print('---------------You have the following error-------------\n')


if __name__ == '__main__':
    main()

Notice

Вам также необходимо разрешить вашей учетной записи службы получать доступ к API Google при использовании делегирования по всему домену, установив Управление доступом клиента API в своей учетной записи G Suite.

1 голос
/ 16 апреля 2020

Вы не ломаете себе голову ... Просто используйте электронную почту и библиотеки smtplib. Очень простая и забавная отправка электронной почты через Python, если вы спросите меня. Я дал мой код ниже, и вы должны разработать свой собственный код на основе этого. Если это сработает, просто дайте мне знать - я буду счастлив. вот оно ....

    import email, smtplib, os, time, fnmatch
    from datetime import date, timedelta
    from email.mime.text import MIMEText
    from email.mime.image import MIMEImage
    from email.mime.multipart import MIMEMultipart

    def sendMailTo(recepient_id, today):

      login_id = 'myemailID@gmail.com'
      login_pwd = "mypassword"
      fro_ = login_id
      s_name = 'smtp.gmail.com'
      s_port = 587

      fileList = []
      fi_type = '*.pdf'
      file_path = "C:\\Myfolder\\Subfolder"

      srvr = smtplib.SMTP(s_name, s_port)
      srvr.ehlo()
      srvr.starttls()
      srvr.ehlo()
      srvr.login(login_id, login_pwd)

      sub = "Your subject here"
      # loading MIMEMultipart obj onto outer var
      outer = MIMEMultipart('alternative')
      outer["From"] = 'Your company/Personal Name'
      outer["To"] = recepient_id 
      outer['Subject'] = sub

      # storing only pdf files          
      fileList = fnmatch.filter(os.listdir(file_path), fi_type)

      for fi in fileList:
        fi_name = os.path.join(file_path, fi)
        fp = open(fi_name, 'rb')
        img = MIMEImage(fp.read(), _subtype='jpg')
        fp.close()
        img.add_header('Content-disposition', "attachment", filename = fi)
        outer.attach(img)

      #start sending email with attachment with original file name
      srvr.sendmail(fro_, recepient_id, outer.as_string())

    part = None
    outer = None
    srvr.quit()
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...