python 3.6 gmail API?发送带有附件的电子邮件

Jin*_*now 1 python email email-attachments python-3.x gmail-api

该python 3脚本假设用于创建电子邮件,将单个文件(使用其url)附加到该电子邮件并发送。它发送了电子邮件,但是create_message_with_attachment()

TypeError:附加内容在非分段有效载荷的邮件上无效

我确实阅读了Google文档。谈论它的堆栈线程专注于精美的附件样式,同时在其顶部混合了python版本的不同语法。

下面的代码是几个来源的拼凑而成。我努力使他们一起参加create_message_with_attachment()

例如,我不知道是否应包含此代码(来自于此代码的create_message_without_attachment()。底部的Cf)

raw = base64.urlsafe_b64encode(msg.as_bytes())
raw = raw.decode()
body = {'raw': raw}
return body
Run Code Online (Sandbox Code Playgroud)

带有附件代码的创建消息:

import httplib2
import os
import oauth2client
from oauth2client import client, tools
import base64
from email import encoders

#needed for attachment
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText

#needed for gmail service
from apiclient import errors, discovery  

#The scope URL for read/write access to the gmail api 
SCOPES = 'https://www.googleapis.com/auth/gmail.send'

CLIENT_SECRET_FILE = 'client_secret.json'
APPLICATION_NAME = 'Gmail API Python Send Email'


def get_credentials():
    # If needed create folder for credential
    home_dir = os.path.expanduser('~') #>> C:\Users\me
    credential_dir = os.path.join(home_dir, '.credentials') # >>C:\Users\me\.credentials   (it's a folder)
    if not os.path.exists(credential_dir):
        os.makedirs(credential_dir)  #create folder if doesnt exist
    credential_path = os.path.join(credential_dir, 'gmail-python-email-send.json')

    #Store the credential
    store = oauth2client.file.Storage(credential_path)
    credentials = store.get()

    if not credentials or credentials.invalid:
    # Create a flow object. (it assists with OAuth 2.0 steps to get user authorization + credentials)
        flow = client.flow_from_clientsecrets(CLIENT_SECRET_FILE, SCOPES)
        flow.user_agent = APPLICATION_NAME
        credentials = tools.run_flow(flow, store)
        print('Storing credentials to ' + credential_path)

    return credentials



def SendMessage(sender, to, subject, msgHtml, msgPlain):
    credentials = get_credentials() 

    http = httplib2.Http()  # Create an httplib2.Http object to handle our HTTP requests, and authorize it using credentials.authorize()

    # http is the authorized httplib2.Http() 
    http = credentials.authorize(http)

    service = discovery.build('gmail', 'v1', http=http)

    message_with_attach = create_message_without_attachment(sender, to, subject, msgHtml, msgPlain)
    SendMessageInternal(service, "me", message_with_attach)


def SendMessageInternal(service, user_id, message): 
    try:
        message = (service.users().messages().send(userId=user_id, body=message).execute())  ####need  to get user_id before

        message_ID = message['id']
        print(f'Message Id: {message_ID}')
        return [message, message_ID] #return value as list
    except errors.HttpError as error:
        print(f'An error occurred: {error}')    

def create_message_with_attachment(sender, to, subject, msgHtml, msgPlain):

    # multipart container can contain other MIME parts.  (attachment will be independent of the multipart/alternative)
    msg = MIMEMultipart('alternative')
    msg['To'] = to
    msg['From'] = sender
    msg['Subject'] = subject

    # convert both part to a MIME compatible string
    part1 = MIMEText(msgPlain, 'plain') 
    part2 = MIMEText(msgHtml, 'html')

    # create .txt attachment
    filePath=r"C:\Users\me\Desktop\test_Attachment.txt"
    myFile=open(filePath, "rb")
    attachment= MIMEApplication(myFile.read())
    msg.set_payload(myFile) # 
    myFile.close()
    msg.set_payload(myFile) # 
    myFile.close()

    #This will add a header that looks like: "Content-Disposition: attachment; filename="test_Attachment.txt" "
    attachment.add_header('content-disposition', 'attachment', filename = ('utf-8', '', 'test_Attachment.txt'))

    # Attach parts into message container.
    msg.attach(attachment)
    msg.attach(part1)
    msg.attach(part2)

    # Encode the payload using Base64.
    raw = encoders.encode_base64(msg)
    return raw


def main():
    to = "youremail@gmail.com"
    sender = "myemail@gmail.com"
    subject = "subject test1"
    msgHtml = r'Hi<br/>Html <b>hello</b>'
    msgPlain = "Hi\nPlain Email"
    message_text= "this is message text"
    SendMessage(sender, to, subject, msgHtml, msgPlain)


if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

此函数在以下代码中成功发送了没有附件的电子邮件:

def create_message_without_attachment (sender, to, subject, msgHtml, msgPlain):
    msg = MIMEMultipart('alternative')
    msg['Subject'] = subject
    msg['From'] = sender
    msg['To'] = to
    msg.attach(MIMEText(msgPlain, 'plain'))
    msg.attach(MIMEText(msgHtml, 'html'))

    raw = base64.urlsafe_b64encode(msg.as_bytes())
    raw = raw.decode()
    body = {'raw': raw}
    return body
Run Code Online (Sandbox Code Playgroud)

Jin*_*now 5

Edit1(避免重复相同的答案):在答案中,您将找到发送带有(或不带有)附件的电子邮件所需的代码(和说明)。

Edit2:由于randomfigure改进了代码