如何通过gmail-api for python发送HTML格式化电子邮件

And*_*rew 25 html python gmail mime-message gmail-api

使用GMail API中的示例代码示例:发送邮件,并在遵循身份验证规则后,通过gmail帐户发送以编程方式生成的电子邮件非常简单.该示例中不明显的是如何将该电子邮件设置为HTML格式.


问题

如何使用python在我的gmail-api发送消息中获取HTML格式?

我有这个...

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
Run Code Online (Sandbox Code Playgroud)

来自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's 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's 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='cbsd.tools@gmail.com')
    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='cbsd.tools@gmail.com')
    cli = parser.parse_args()
    pprint(dir(cli))

    main(cli)
Run Code Online (Sandbox Code Playgroud)

我尽可能尝试,使用此代码及其变体,我无法获得html格式的代码,也无法获得简单的转义字符来创建回车所需的位置.


这是不起作用的

尝试以下方法也不起作用:

  1. 修改line 69以添加其他消息字典参数...即.
    • {'raw': base64.urlsafe_b64encode(message.as_string()), 'payload': {'mimeType': 'text/html'}}
    • 正如GMail API Docs中所述
    • 在此输入图像描述
  2. 在消息文本中添加各种转义反斜杠:
    • \n...即:\\n也不是\\\n,只是呈现为那些确切的字符
    • 添加<br> </br> <br/>没有添加新行,只是呈现为那些确切的字符
    • 添加\r没有添加新行,只是呈现为确切的字符

原因这不是一个重复的问题

And*_*rew 24

经过大量的挖掘后,我开始寻找消息处理的python方面,并注意到python对象实际上构建了要将base64编码发送到gmail-api消息对象构造函数的消息.

见上文第63行: message = MIMEText(message_text)

修改了标头值和有效负载dict(它是message对象的一个成员)的所有尝试之后,最终对我有用的一个技巧是set(line 63):

  • message = MIMEText(message_text, 'html')< - 添加'html'作为MIMEText对象构造函数的第二个参数

Google为其gmail API 提供的默认代码仅告诉您如何发送纯文本电子邮件,但它们隐藏了他们如何执行此操作.翼... message = MIMEText(message_text)

我不得不查找python类email.mime.text.MIMEText对象.您可以在这里看到MIMEText对象的构造函数的这个定义:

  • class 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())}
Run Code Online (Sandbox Code Playgroud)


Jan*_*ake 5

尝试这个:

    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'
Run Code Online (Sandbox Code Playgroud)

  • 是的,如果需要,那就太棒了。在问题结束时,我特别声明我对多部分 mime 类型不感兴趣,并且这个问题与纯 html 格式有关。对于更强大、更复杂的 API 方法来说,这是一个很好的答案,这对于这个项目和问题来说是过度设计的。我确实喜欢它作为不同问题的一般答案,尤其是 try catch 位。 (2认同)

ala*_*erg 5

接受的答案有效,但在我深入这个兔子洞的旅程中,我找到了放置原始问题中的有效负载的正确位置,所以这里有一个完整的示例。我正在使用具有域范围委派的服务帐户:

import base64 
from googleapiclient.discovery import build
from google.oauth2 import service_account
from email.message import EmailMessage

SCOPES = ['https://www.googleapis.com/auth/gmail.send']
CREDS = service_account.Credentials.from_service_account_file(
        serviceAcct, scopes=SCOPES, subject=senderEmail)

with build('gmail', 'v1', credentials=CREDS) as service:
    msg = EmailMessage()
    content="Message body in <b>html</b> format!"

    msg['To'] = recipientEmail
    msg['From'] = senderEmail
    msg['Subject'] = 'Gmail API test'
    # Use this for plain text
    # msg.set_content(content)
    # Otherwise, use this for html
    msg.add_header('Content-Type','text/html')
    msg.set_payload(content)

    encodedMsg = base64.urlsafe_b64encode(msg.as_bytes()).decode()

    try:
        sendMsg = service.users().messages().send(
            userId=senderEmail,
            body={ 'raw': encodedMsg }
        ).execute()
        print('Msg id:', sendMsg['id'])
    except Exception as e:
        print('Error:', e)
Run Code Online (Sandbox Code Playgroud)