pythonemailpdfoutlookthunderbird

[Python]Why are email pdf attachments not showing up on Outlook/Thunderbird, while they do on Gmail? (Sent from a Python environment)


I've just joined a project and have been trying to figure why some emails are showing up as they should on Gmail but when I open then with a client like Thunderbird or Outlook the attached PDFs do now show up. As an additional detail if I forward the mail from Thunderbird/Tutlook to a Gmail account the attached pdf will appear and if I send it back to the Thunderbird/Outlook - connected account it will again appear, so Gmail fixes something that's wrong in the code.

This is my second time dealing with emails, the first being mostly copying some code to see if it works, so if you're willing to explain it to me in addition to helping me fix it, I'd appreciate it greatly. I'll post the code here and then add some additional information on what I tried below, to keep this a bit cleaner. So, here's the code:

from email.message import EmailMessage
from email import encoders
from email.mime.base import MIMEBase
import smtplib



msg = EmailMessage()
msg['Subject'] = subject
msg['From'] = "someaddress"
msg['To'] = user_email
msg.set_content('Certification')
msg.add_alternative("""<!DOCTYPE html>
        <html>
            <body>
                Stuff...
            </body>
        </html>
        """, subtype='html')

filename = 'somefilename'
pdf_filename = 'certificate.pdf'
with open(filename, "rb") as attachment:
    part = MIMEBase("application", "octet-stream")
    part.set_payload(attachment.read())

encoders.encode_base64(part)
part.add_header(
    "Content-Disposition",
    "attachment", filename=pdf_filename
)
try:
    msg.attach(part)
    with smtplib.SMTP('someIP', port) as smtp:
        smtp.send_message(msg)

I've seen some similar issues (or actually the same issue) before, and some solutions suggested using a MIMEMultipart-mixed message object instead of an email one like this: msg=MIMEMultipart('mixed') instead of msg = EmailMessage() but because add_alternative is not a MIMEMultipart method, I cannot do that without changing that part. (The above was suggested on this post - which is exactly the same issue as mine, but unfortunately I could not use the same fix)

What I tried doing was calling a msg.make_mixed() below msg=Email.Message() hoping that the mixed type (I don't understand email types yet) would solve the problem, but when I tried sending an email that way I got a Status=4, Failed to send file, error.

I would also really appreciate if you could offer any suggestion for a resource to learn some more about sending and receiving emails (from a python perspective).

Thank you!


Solution

  • The problem here is that you have directly attached a pre-built MIME part to a multipart/alternative message. It ends in an incorrect message that may be poorly processed by mail readers.

    In the email.message interface, you should use the add_attachement method. It will handle the base64 encoding and will change the message into a multipart/mixed one:

    with open(filename, "rb") as attachment:
        msg.add_attachment(attachment.read(), maintype='application',
               subtype='octet-stream', filename=pdf_filename)
    
    try:
        with smtplib.SMTP('someIP', port) as smtp:
            smtp.send_message(msg)