python - 使用 python 通过 gmail 发送电子邮件
问题描述
我从实现37201250开始,但很快意识到自 2017 年以来情况发生了变化。我设法使用 googleapiclient 来实现。我可以发送经过身份验证的普通邮件和 html 邮件。这些是我需要帮助的事情:
附件:邮件通过但附件被剥离。当我检查我的 gmail 帐户时,我看到发送的邮件没有附件,并且通过 UI 发送的电子邮件按预期到达。
错误: “errors.HttpError as error:”行在 pylint 中显示未定义。我需要 googleapiclient 中的等效功能吗?
刷新:目前刷新需要用户交互,我认为来自 37201250 的原始脚本使用 oauth2client 以编程方式进行。如何在不使用 googleapiclient 的用户交互的情况下实现这一点?
这是我创建的代码:
import os
import pickle
import base64
import mimetypes
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email import encoders
from email.message import Message
from email.mime.audio import MIMEAudio
from email.mime.base import MIMEBase
from email.mime.image import MIMEImage
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from googleapiclient.discovery import build
from google_auth_oauthlib.flow import InstalledAppFlow
from google.auth.transport.requests import Request
def GetCredentials(CredentialFilePrefix):
creds=None
CFP=CredentialFilePrefix+'.pkl'
if os.path.exists(CFP):
print("found file "+CFP+",loading...")
with open(CFP, 'rb') as token:
creds = pickle.load(token)
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token:
print("Opening web UI for refreshing token...")
creds.refresh(Request())
else:
CFJ=CredentialFilePrefix+'.json'
print("Opening web UI for creating token from "+CFJ+"...")
flow = InstalledAppFlow.from_client_secrets_file(
CFJ, Scopes)
creds = flow.run_local_server(port=0)
print('Created token')
# Save the credentials for the next run
print('Saving...')
with open(CFP, 'wb') as token:
pickle.dump(creds, token)
print('Saved token')
else:
print("loaded successfully")
return creds
def CreateHtmlMessage(sender,to,subject,message_text,attached=""):
msg = MIMEMultipart('alternative')
msg['Subject'] = subject
msg['From'] = sender
msg['To'] = to
msg.attach(MIMEText(message_text, 'html'))
if len(attached)>0:
my_mimetype, encoding = mimetypes.guess_type(attached)
if my_mimetype is None or encoding is not None:
my_mimetype = 'application/octet-stream'
print("Attachment mimetype:"+my_mimetype)
main_type, sub_type = my_mimetype.split('/', 1)
if main_type == 'text':
temp = open(attached, 'r') # 'rb' will send this error: 'bytes' object has no attribute 'encode'
attachment = MIMEText(temp.read(), _subtype=sub_type)
temp.close()
elif main_type == 'image':
temp = open(attached, 'rb')
attachment = MIMEImage(temp.read(), _subtype=sub_type)
temp.close()
elif main_type == 'audio':
temp = open(attached, 'rb')
attachment = MIMEAudio(temp.read(), _subtype=sub_type)
temp.close()
elif main_type == 'application' and sub_type == 'pdf':
temp = open(attached, 'rb')
attachment = MIMEApplication(temp.read(), _subtype=sub_type)
temp.close()
elif main_type == 'application' and sub_type == 'vnd.openxmlformats-officedocument.wordprocessingml.document':
temp = open(attached, 'rb')
attachment = MIMEApplication(temp.read(), _subtype=sub_type)
temp.close()
else:
attachment = MIMEBase(main_type, sub_type)
temp = open(attached, 'rb')
attachment.set_payload(temp.read())
temp.close()
filename = os.path.basename(attached)
attachment.add_header('Content-Disposition', 'attachment', filename=filename) # name preview in email
msg.attach(attachment)
raw = base64.urlsafe_b64encode(msg.as_bytes())
raw = raw.decode()
body = {'raw': raw}
return body
def SendMessage(encoded,creds):
service = build('gmail', 'v1', credentials=creds)
user_id="me"
try:
message = (service.users().messages().send(userId=user_id, body=encoded).execute())
print('Message Id: %s' % message['id'])
return message
except errors.HttpError as error:
print('An error occurred: %s' % error)
return ""
#Global Variables
Toolname='SendMail'
ToolVersion='0.5.20201223.1'
Scopes = 'https://www.googleapis.com/auth/gmail.send'
Client_Secret_File = 'credentials'
App_Name = 'MailSender'
to = "xxx@test.com"
sender = "xxx@gmail.com"
subject = "Test Mail with attachment"
msgHtml = "Hi<br/><b>Html Email</b>"
msgPlain = "Hi\nPlain Email"
attachment="doc.pdf"
#Global Variables
def main():
credentials = None
credentials = GetCredentials(Client_Secret_File)
print("Got credentials")
msgEncoded=CreateHtmlMessage(sender, to, subject,msgHtml,attachment)
SendMessage(msgEncoded,credentials)
'/path/to/file.pdf')
if __name__ == '__main__':
main()
解决方案
推荐阅读
- aws-lambda - 如何在 CodeBuild 中为 Lambda 函数添加 Python 库依赖项
- java - Spring Boot JPA 获取列表并向其中添加项目会引发错误
- spotfire - TIBCO Spotfire:错误消息:无法在 Spotfire.Dxp.Data 创建 DataTable ImportException:无法创建 DataTable(HRESULT:80131500)
- c# - CSVHelper - 将名称从 CSV 导入具有相同名称属性的对象
- python - 如何从不同的文件调用方法而不在python中导入它
- python - 通过循环的 kafka 消费者获取消息和手动调用 poll 有什么区别?
- java - 绘制/绘制数学函数时 drawPolyLine() 与 drawLine()
- angular - 在 Angular Web App 中添加数据连接器列表,就像 Power BI 中的“获取数据”一样
- java - 如何从地图中获取偶数值,然后将值键添加到列表中?
- amazon-redshift - 用于动态 json 文件的 Redshift JSONPaths 文件