0

For a personal project I'm trying to automate sending emails. I need to attach PDF's to these emails but for whatever reason, they won't. With the following code, the emails will send fine but there will be no PDF attached. Pretty much every article I've read uses the same code but for whatever reason it does not work with my script.

The closest I've gotten it to work is with this code because it can attach ".txt" documents but when I try and change the "attachment; filename=..." to a pdf ending it no longer attaches.

A lot of the articles that I have read also use .add_attach(). I cannot even test if that is the missing part that I need to finish this problem. I have noticed it in the official python documentation but I get an error every time I try to use it because it claims that Python does not have a function like that.

from email.mime.base import MIMEBase
import pickle
import os
import base64
import googleapiclient.discovery
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.application import MIMEApplication
from email.mime.image import MIMEImage
from email.message import EmailMessage
import mimetypes
import imghdr

# Get the path to the pickle file
home_dir = os.path.expanduser('~')
pickle_path = os.path.join(home_dir, 'gmail.pickle')

# Load our pickled credentials
creds = pickle.load(open(pickle_path, 'rb'))

# Build the service
service = googleapiclient.discovery.build('gmail', 'v1', credentials=creds)

# Create a message
rec_email = 'sturner@woosox.com'
my_email = 'woosoxsuiteinfo@gmail.com'
msg = MIMEMultipart('alternative')
msg['Subject'] = 'Testing'
msg['From'] = my_email
msg['To'] = rec_email
msgPlain = "Testing Attatchements"
msg.attach(MIMEText(msgPlain, 'plain'))

#PROBLEM AREA HERE
part = MIMEBase('application', "octet-stream")
part.set_payload(open("Something.pdf", "rb").read())
encoders.encode_base64(part)
part.add_header('Content-Disposition', 'attachment; filename="Something.pdf"')
msg.attach(part)

raw = base64.urlsafe_b64encode(msg.as_bytes())
raw = raw.decode()
body = {'raw': raw}

message1 = body
message = (
    service.users().messages().send(
        userId="me", body=message1).execute())
print('Message Id: %s' % message['id'])```
  • Hi Sturner. Here's a similar question, https://stackoverflow.com/q/28821487/246801, and both answers address things you're doing in your script that you could change, and see if it works. – Zach Young Jun 14 '22 at 16:43
  • Along the lines of the first answer in the previous link/SO, `alternative` is not what you want, https://stackoverflow.com/q/3902455/246801. The key is that the all the different kinds of a MIMEMultipart message compose a _tree_. Have you tried just making a test email, sending from/to Gmail and inspecting the source with **Show original**? I just sent myself a PDF and can indeed see many parts of the MIMEMessage. – Zach Young Jun 14 '22 at 17:00
  • Also, the Gmail API has a completely separate mechanism for uploading, https://developers.google.com/gmail/api/guides/uploads and https://github.com/googleapis/google-api-python-client/blob/main/docs/media.md, if that's something you want to pursue. – Zach Young Jun 14 '22 at 17:03
  • Zach you are my lord and savior. I just had to change "alternative" to "mixed" and it work! You are the best – Sturner Jun 14 '22 at 19:14

0 Answers0