Sending email via gmail with python fails to send attachments

ぃ、小莉子 提交于 2021-02-11 16:35:40

问题


I started off by implementing 37201250 but quickly realized that things have changed since 2017. I managed to implement using googleapiclient. I can send authenticated plain and html mails. However for mail with attachments, mail goes through but attachment is stripped. Now error is returned from the functions. When I check my gmail account I see that the sent mails went through without attachments and sending through the UI e-mails arrive as expected. Could somebody tell what I am missing?

The code I use is provided below:

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)

来源:https://stackoverflow.com/questions/65436970/sending-email-via-gmail-with-python-fails-to-send-attachments

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!