以编程方式发布包含 HTML 和用户指定的明文正文的 Gmail 草稿

Programmatically posting Gmail draft with both HTML and plaintext bodies specified by user

我正在使用 Gmail API 在 Python 中自动创建 Gmail 草稿。我需要创建 HTML 格式的电子邮件,但我个人也需要创建纯文本回退,因为这是正确的做法。

我以为我已经完成了上述所有工作,直到我尝试使明文回退与 HTML 略有不同。似乎 Google 自行为我创建明文回退,而不是使用我提供的那个,所以如果我的 html 正文是 <HTML><BODY>HTML Body</BODY></HTML> 而我的明文正文是 Plaintext body,最终的明文主体将是 HTML Body,丢弃我提供的明文。

我的问题:有没有人知道如何让 Gmail API 使用明文 I 提供,而不是比自动为我生成后备?

我注意到的一个相关项目:如果我以不同的顺序附加 HTML 和明文正文,则会发生相反的情况 - GMail 将根据我的明文自动生成 HTML 正文。所以好像只关注最后一个attached body

我正在使用的代码的精简版本:

import base64
import os
import httplib2
import oauth2client
from oauth2client import client
from oauth2client import tools
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from pathlib import Path
from apiclient import errors
from apiclient import discovery

SCOPES = 'https://mail.google.com/'
CLIENT_SECRET_FILE = 'client_id.json'
APPLICATION_NAME = 'Test Client'

def get_credentials():
    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 = oauth2client.file.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 CreateDraft(service, user_id, message_body):
    message = {'message': message_body}
    draft = service.users().drafts().create(userId=user_id, body=message).execute()
    return draft


def CreateTestMessage(sender, to, subject):
    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = sender
    msg['To'] = to
    plain_text = "Text email message. It's plain. It's text."
    html_text = """\
<html>
  <head></head>
  <body>
    <p>HTML email message</p>
    <ol>
        <li>As easy as one</li>
        <li>two</li>
        <li>three!</li>
    </ol>
    <p>Includes <a href="http://whosebug.com/">linktacular</a> goodness</p>
  </body>
</html>
"""

    # Swapping the following two lines results in Gmail generating HTML
    # based on plaintext, as opposed to generating plaintext based on HTML
    msg.attach(MIMEText(plain_text, 'plain')) 
    msg.attach(MIMEText(html_text, 'html'))

    print('-----\nHere is the message:\n\n{m}'.format(m=msg))
    encoded = base64.urlsafe_b64encode(msg.as_string().encode('UTF-8')).decode('UTF-8') 
    return {'raw': encoded}


def main():
    credentials = get_credentials()
    http = credentials.authorize(httplib2.Http())
    service = discovery.build('gmail', 'v1', http=http)

    my_address = 'example@gmail.com' # Obscured to protect the culpable

    test_message = CreateTestMessage(sender=my_address,
                                 to='example@gmail.com',
                                 subject='Subject line Here')

    draft = CreateDraft(service, my_address, test_message)


if __name__ == '__main__':
    main()

更新:这是 example gists 我发送 Gmail 的内容与 Gmail 发送的内容,在HTML-then-plaintext 和 plaintext-then-HTML 命令(产生不同的结果)

TL;DR: 没有。

草稿对象与网络 UI 和移动 UI 共享,如果 text/plain 不仅仅是 text/html 的简单转换,那么尽快因为用户使用任何其他 UI 来编辑特殊定制将丢失的消息。使用草稿 UI 的原因是允许用户在其他界面之间共享这些草稿。

如果您不关心 about/want 那个能力不使用草稿,只是在最后发送()它,像 SMTP-MSA 允许更多的灵活性。