【发布时间】:2017-07-24 21:19:20
【问题描述】:
这个 python 3 脚本假设创建一封电子邮件,将单个文件(使用它的 url)附加到它并发送它。它发送电子邮件,但create_message_with_attachment() 出现问题
TypeError: Attach is not valid on a message with a non-multipart payload
我确实阅读了谷歌文档。讨论它的堆栈线程专注于花哨的附件样式,同时混合了 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
带有附件代码的创建消息:
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()
此功能成功在此代码中发送不带附件的电子邮件:
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
【问题讨论】:
-
可以添加日志吗?您可能希望通过添加
msg.set_payload(contents)和encoders.encode_base64(msg)来关注此报告票证中的solution。希望这会有所帮助 -
@Mr.Rebot 非常感谢您提供的宝贵链接!我使用我的解释更新了代码(那个人没有发布整个代码,所以我不太理解他的“我还需要添加第二行如下”。代码返回
TypeError: Attach is not valid on a message with a non-multipart payload我也没有了解我是否应该添加还从正在工作的函数中添加raw =....部分(参见我的问题底部的 create_message_without_attachment()) -
你会在这里找到答案:stackoverflow.com/a/37267330/1486850
标签: python python-3.x email gmail-api email-attachments