首页 > 解决方案 > 使用 python 通过 gmail 发送电子邮件

问题描述

我从实现37201250开始,但很快意识到自 2017 年以来情况发生了变化。我设法使用 googleapiclient 来实现。我可以发送经过身份验证的普通邮件和 html 邮件。这些是我需要帮助的事情:

  1. 附件:邮件通过但附件被剥离。当我检查我的 gmail 帐户时,我看到发送的邮件没有附件,并且通过 UI 发送的电子邮件按预期到达。

  2. 错误: “errors.HttpError as error:”行在 pylint 中显示未定义。我需要 googleapiclient 中的等效功能吗?

  3. 刷新:目前刷新需要用户交互,我认为来自 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()

标签: pythonemail

解决方案


推荐阅读