我想发送带有内容ID附件的html电子邮件(图片直接显示在邮件中),而Content-Disposition附件则是xls文件。
根据我使用的客户端邮件,xls文件不可见(例如在iPhone,iPad或Samsung上)。
我想我没有在邮件的正确部分中包含xls文件,但是当我尝试在MIMEMultipart('alternative')
之前包含它时,它不起作用。
有人对以下代码中的问题来源有任何疑问吗?
import base64
import httplib2
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import mimetypes
from email.mime.image import MIMEImage
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.application import MIMEApplication
from apiclient.discovery import build
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run
html = """\
<html>
<head></head>
<body>
<p>Hi!<br>
XXX <br><br>
Hereunder a short overview of market evolution :<br>
<img src="cid:image1" height="600" width="600">
</p>
</body>
</html>
"""
to='test@gmail.com';
subject='XXX';
message_main = html;
attachment_paths = [('test.png'), '<image1>'),
('2910e0f.xls', False)]
# Check https://developers.google.com/gmail/api/auth/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/gmail.compose'
# Location of the gmail.storage
STORAGE = Storage('gmail.storage')
# Start the OAuth flow to retrieve credentials
flow = flow_from_clientsecrets(CLIENT_SECRET_FILE, scope=OAUTH_SCOPE)
http = httplib2.Http()
# Try to retrieve credentials from storage or run the flow to generate them
credentials = STORAGE.get()
if credentials is None or credentials.invalid:
credentials = run(flow, STORAGE, http=http)
# Authorize the httplib2.Http object with our credentials
http = credentials.authorize(http)
## Save credentials to storage
# STORAGE.put(credentials)
# Build the Gmail service from discovery
gmail_service = build('gmail', 'v1', http=http)
message = MIMEMultipart('related') # 'alternative', 'multipart', 'mixed', related
message['to'] = to
message['from'] = "YYY@gmail.com"
message['subject'] = subject
message.preamble = 'This is a multi-part message in MIME format.'
# Encapsulate the plain and HTML versions of the message body in an
# 'alternative' part, so message agents can decide which they want to display.
msgAlternative = MIMEMultipart('alternative')
message.attach(msgAlternative)
msg1 = MIMEText(message_main, 'plain')
msg2 = MIMEText(message_main, 'html')
msgAlternative.attach(msg1)
msgAlternative.attach(msg2)
for filename, link in attachment_paths:
print '----'
print filename
print link
content_type, encoding = mimetypes.guess_type(filename)
if content_type is None or encoding is not None:
content_type = 'application/octet-stream'
main_type, sub_type = content_type.split('/', 1)
if main_type == 'text':
fp = open(filename, 'rb')
msg = MIMEText(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'image':
fp = open(filename, 'rb')
msg = MIMEImage(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'audio':
fp = open(filename, 'rb')
msg = MIMEAudio(fp.read(), _subtype=sub_type)
fp.close()
else:
fp = open(filename, 'rb')
msg = MIMEBase(main_type, sub_type)
msg.set_payload(fp.read())
fp.close()
if not link:
# msg.add_header('Content-Disposition', 'attachment', filename=filename)
# message.attach(msg)
# pdf = open(filename, 'rb').read()
# msgPdf = MIMEApplication(pdf, 'pdf') # pdf for exemple
# msgPdf.add_header('Content-ID', '<pdf1>') # if no cid, client like MAil.app (only one?) don't show the attachment
msg.add_header('Content-Disposition', 'attachment', filename=filename)
# msg.add_header('Content-Disposition', 'inline', filename=filename)
else:
# Define the image's ID as referenced above
msg.add_header('Content-ID', link)
msg.add_header('Content-Disposition', 'attachment', filename=filename)
message.attach(msg)
body = {'raw': base64.urlsafe_b64encode(message.as_string())}
# body = {'raw': base64.b64encode(message.as_string())}
# send it
try:
message = (gmail_service.users().messages().send(userId="me", body=body).execute())
print('Message Id: %s' % message['id'])
print(message)
except Exception as error:
print('An error occurred: %s' % error)
答案 0 :(得分:0)
解决方案包括将初始多部分容器更改为混合并通过两个步骤附加文件:
MIMEMultipart('alternative')
简单附件声明MIMEMultipart('alternative')
附件声明后(主要是留言中的图片)您可以在下面找到正确的代码:
import base64
import httplib2
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
import mimetypes
from email.mime.image import MIMEImage
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.application import MIMEApplication
from apiclient.discovery import build
from oauth2client.client import flow_from_clientsecrets
from oauth2client.file import Storage
from oauth2client.tools import run
html = """\
<html>
<head></head>
<body>
<p>Hi!<br>
XXX <br><br>
Hereunder a short overview of market evolution :<br>
<img src="cid:image1" height="600" width="600">
</p>
</body>
</html>
"""
to='test@gmail.com';
subject='XXX';
message_main = html;
attachment_paths_html = [('test.png'), '<image1>')]
attachment_paths_mixed = [('2910e0f.xls', '2910e0f.xls')]
# Check https://developers.google.com/gmail/api/auth/scopes for all available scopes
OAUTH_SCOPE = 'https://www.googleapis.com/auth/gmail.compose'
# Location of the gmail.storage
STORAGE = Storage('gmail.storage')
# Start the OAuth flow to retrieve credentials
flow = flow_from_clientsecrets(CLIENT_SECRET_FILE, scope=OAUTH_SCOPE)
http = httplib2.Http()
# Try to retrieve credentials from storage or run the flow to generate them
credentials = STORAGE.get()
if credentials is None or credentials.invalid:
credentials = run(flow, STORAGE, http=http)
# Authorize the httplib2.Http object with our credentials
http = credentials.authorize(http)
## Save credentials to storage
# STORAGE.put(credentials)
# Build the Gmail service from discovery
gmail_service = build('gmail', 'v1', http=http)
message = MIMEMultipart('mixed')
message['to'] = to
message['from'] = "YYY@gmail.com"
message['subject'] = subject
message.preamble = 'This is a multi-part message in MIME format.'
for filename, name in attachment_paths_mixed:
print '----'
print filename
print name
content_type, encoding = mimetypes.guess_type(filename)
if content_type is None or encoding is not None:
content_type = 'application/octet-stream'
main_type, sub_type = content_type.split('/', 1)
if main_type == 'text':
fp = open(filename, 'rb')
msg = MIMEText(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'image':
fp = open(filename, 'rb')
msg = MIMEImage(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'audio':
fp = open(filename, 'rb')
msg = MIMEAudio(fp.read(), _subtype=sub_type)
fp.close()
else:
fp = open(filename, 'rb')
msg = MIMEBase(main_type, sub_type)
msg.set_payload(fp.read())
fp.close()
msg.add_header('Content-Disposition', 'attachment', filename=name)
message.attach(msg)
# Encapsulate the plain and HTML versions of the message body in an
# 'alternative' part, so message agents can decide which they want to display.
msgAlternative = MIMEMultipart('alternative')
message.attach(msgAlternative)
msg1 = MIMEText(message_main, 'plain')
msg2 = MIMEText(message_main, 'html')
msgAlternative.attach(msg1)
msgAlternative.attach(msg2)
for filename, link in attachment_paths_html:
print '----'
print filename
print link
content_type, encoding = mimetypes.guess_type(filename)
if content_type is None or encoding is not None:
content_type = 'application/octet-stream'
main_type, sub_type = content_type.split('/', 1)
if main_type == 'text':
fp = open(filename, 'rb')
msg = MIMEText(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'image':
fp = open(filename, 'rb')
msg = MIMEImage(fp.read(), _subtype=sub_type)
fp.close()
elif main_type == 'audio':
fp = open(filename, 'rb')
msg = MIMEAudio(fp.read(), _subtype=sub_type)
fp.close()
else:
fp = open(filename, 'rb')
msg = MIMEBase(main_type, sub_type)
msg.set_payload(fp.read())
fp.close()
# Define the image's ID as referenced above
msg.add_header('Content-ID', link)
message.attach(msg)
body = {'raw': base64.urlsafe_b64encode(message.as_string())}
# body = {'raw': base64.b64encode(message.as_string())}
# send it
try:
message = (gmail_service.users().messages().send(userId="me", body=body).execute())
print('Message Id: %s' % message['id'])
print(message)
except Exception as error:
print('An error occurred: %s' % error)