Как отправить отправленные HTML-форматированные письма через gmail-api для python
Используя пример кода из Пример API GMail: Отправка почты, а после следующих правил аутентификации достаточно просто отправить программно сгенерированный электронной почты через учетную запись gmail. Что не является очевидным из этого примера, так это то, как настроить это письмо в формате HTML.
Вопрос
Как получить форматирование HTML в сообщениях отправки gmail-api с помощью python?
У меня есть это...
message_body = "Hello!\nYou've just received a test message!\n\nSincerely,\n-Test Message Generator\n"
, и я хочу, чтобы это было...
Hello!
You've just received a test message!
Sincerely,
-Test Message Generator
Пример исходного кода из GMail-API
Ниже приведена слегка измененная версия примера, но все еще работает:
import argparse
import base64
from pprint import pformat
from pprint import pprint
import httplib2
import os
from email.MIMEMultipart import MIMEMultipart
from email.MIMEText import MIMEText
from apiclient import discovery
from oauth2client import client
from oauth2client import tools
from oauth2client.file import Storage
SCOPES = 'https://mail.google.com/'
CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Test EMail App'
def get_credentials():
"""Gets valid user credentials from storage.
If nothing has been stored, or if the stored credentials are invalid,
the OAuth2 flow is completed to obtain the new credentials.
Returns:
Credentials, the obtained credential.
"""
home_dir = os.path.expanduser('~')
credential_dir = os.path.join(home_dir, '.credentials')
if not os.path.exists(credential_dir):
os.makedirs(credential_dir)
credential_path = os.path.join(credential_dir,
'gmail-python-quickstart.json')
store = Storage(credential_path)
credentials = store.get()
if not credentials or credentials.invalid:
flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
flow.user_agent = APPLICATION_NAME
if flags:
credentials = tools.run_flow(flow, store, flags)
else: # Needed only for compatibility with Python 2.6
credentials = tools.run(flow, store)
print('Storing credentials to ' + credential_path)
return credentials
def create_message(sender, to, cc, subject, message_text):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
message_text: The text of the email message.
Returns:
An object containing a base64url encoded email object.
"""
print(sender + ', ' + to + ', ' + subject + ', ' + message_text)
message = MIMEText(message_text)
message['to'] = to
message['from'] = sender
message['subject'] = subject
message['cc'] = cc
pprint(message)
return {'raw': base64.urlsafe_b64encode(message.as_string())}
def send_message(service, user_id, message_in):
"""Send an email message.
Args:
service: Authorized Gmail API service instance.
user_id: User email address. The special value "me"
can be used to indicate the authenticated user.
message: Message to be sent.
Returns:
Sent Message.
"""
pprint(message_in)
try:
message = (service.users().messages().send(userId=user_id, body=message_in).execute())
pprint(message)
print ('Message Id: %s' % message['id'])
return message
except errors.HttpError, error:
print ('An error occurred: %s' % error)
def main(cli):
"""Shows basic usage of the Gmail API.
Creates a Gmail API service object and outputs a list of label names
of the user Gmail account.
"""
credentials = get_credentials()
http = credentials.authorize(httplib2.Http())
service = discovery.build('gmail', 'v1', http=http)
email_msg = create_message(cli.addr_from, cli.addr_to, cli.addr_cc, cli.subject, cli.message)
msg_out = service.users().messages().send(userId = 'me', body = email_msg).execute()
pprint(msg_out)
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('-m', '--message', help = 'The message to send in the email', default='<MESSAGE = unfinished>')
parser.add_argument('-t', '--addr_to', help = 'the list of comma separated emails to send', default='[email protected]')
parser.add_argument('-s', '--subject', help = 'the email subject', default='<SUBJECT = undefined>')
parser.add_argument('-c', '--addr_cc', help = 'email CC\'s', default='')
parser.add_argument('-f', '--addr_from', help = 'Email address to send from', default='[email protected]')
cli = parser.parse_args()
pprint(dir(cli))
main(cli)
Пробовал, как мог, с помощью этого кода и вариаций на нем, я не мог получить html-форматированный код и не мог получить простые escape-символы для создания возвратов каретки там, где они должны были быть.
Здесь что не работает
Невозможно выполнить следующие действия:
- изменить
line 69
, чтобы добавить дополнительные параметры словаря сообщения... т.е.
-
{'raw': base64.urlsafe_b64encode(message.as_string()), 'payload': {'mimeType': 'text/html'}}
- Как описано здесь в Документах GMail API
-
![введите описание изображения здесь]()
- Добавление в текст сообщения различных сбрасываемых обратных косых черт:
-
\n
... ie: \\n
и \\\n
и просто отображаются как эти точные символы
- Добавление
<br> </br> <br/>
не добавляло новые строки и просто отображалось как эти точные символы
- Добавление
\r
не добавляло новые строки и просто отображалось как этот точный символ
Причины этого не дублируют вопрос
- Эта ссылка SO имеет дело с сообщениями с несколькими/подписанными
- Я не заинтересован в многопользовательской передаче сообщений, потому что это неэлегантное решение. Я хочу, чтобы сообщение WHOLE было
HTML
.
- Кроме того, эта ссылка не имеет принятого ответа, и один из них представляет собой не-ответ, поскольку он просто заявляет, что отправляет в Google сообщение о проблеме.
- Этот вопрос относится к С#, который меня не интересует, поскольку я пишу в python
- Этот файл предназначен для Rails.
Ответы
Ответ 1
После долгих поисков я начал изучать аспекты обработки сообщений на стороне python и заметил, что объект python фактически создает сообщение, которое будет отправлено для кодирования base64, в конструктор объекта сообщения gmail-api.
См. message = MIMEText(message_text)
63 сверху: message = MIMEText(message_text)
Единственный трюк, который наконец-то сработал для меня, после всех попыток изменить значения заголовка и dict полезной нагрузки (который является членом объекта message
), должен был установить (line 63
):
-
message = MIMEText(message_text, 'html')
<- добавить 'html'
в качестве второго параметра конструктора объекта MIMEText
Код по умолчанию, предоставленный Google для их API Gmail, говорит только о том, как отправлять текстовые электронные письма, но они скрывают, как они это делают. ala... message = MIMEText(message_text)
Мне пришлось искать объект класса python email.mime.text.MIMEText
. Вот где вы увидите это определение конструктора для объекта MIMEText:
- класс email.mime.text.MIMEText(_text [, _subtype [, _charset]]) Мы хотим явно передать ему значение в
_subtype
. В этом случае мы хотим передать: 'html'
в качестве _subtype
.
Теперь у вас больше не будет неожиданного переноса слов к вашим сообщениям от Google или к объекту Python mime.text.MIMEText
Фиксированный код
def create_message(sender, to, cc, subject, message_text):
"""Create a message for an email.
Args:
sender: Email address of the sender.
to: Email address of the receiver.
subject: The subject of the email message.
message_text: The text of the email message.
Returns:
An object containing a base64url encoded email object.
"""
print(sender + ', ' + to + ', ' + subject + ', ' + message_text)
message = MIMEText(message_text,'html')
message['to'] = to
message['from'] = sender
message['subject'] = subject
message['cc'] = cc
pprint(message)
return {'raw': base64.urlsafe_b64encode(message.as_string())}
Ответ 2
Попробуйте следующее:
def CreateMessage(emailSubject, emailTo, emailFrom, message_body, emailCc, html_content=None):
try:
message = MIMEMultipart('alternative')
message['to'] = emailTo
message['from'] = emailFrom
message['subject'] = emailSubject
message['Cc'] = emailCc
body_mime = MIMEText(message_body, 'plain')
message.attach(body_mime)
if html_content:
html_mime = MIMEText(html_content, 'html')
message.attach(html_mime)
return {
'raw': base64.urlsafe_b64encode(
bytes(
message.as_string(),
"utf-8")).decode("utf-8")}
except Exception as e:
print('Error in CreateMessage()', e)
return '400'