Trying to update email script

I have a Python script for sending email from a database that worked well for years on Python 2.7. Recently I revised it to work on Python 3.9. All seemed well until I found that attachments weren’t being included when received by iOS devices. A paperclip icon indicates that an attachment is included, but none is actually there.

I’ve been using MIMEMultipart(‘related’) to include embedded graphics as well as any attachments.
Changing it to MIMEMultipart(‘mixed’) includes the attachments in all cases, but it also causes any embedded graphics to repeat as attachments in all cases.

MIMEMultipart(‘alternative’) sends only the attachment.

Ultimately, it appears that my conversion has yet to properly utilize new email features of Python 3 and MIMEMultipart seems to be obsolete. But in spite of a lot of effort, I’ve been unable to come up with a solution. As I look to examples on any number of Python sites, what they load at the beginning varies greatly from one to another. I can’t seem to make any work.

Here’s my current script, which actually does work except as noted above. In actual use, the message, any embedded images and any attachments are all loaded from variables.

#!/usr/bin/python3
import ss
import smtplib
import mimetypes
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.image import MIMEImage
from email.mime.base import MIMEBase
from email import encoders

try:
    strTo = '''Me@GMail.com'''
    strFrom = '''Me@My.com'''
    strCC = ""
    strError = ""
    strImages = ""

    msg = MIMEMultipart('related')
    msg['Subject'] = '''Test'''
    msg['From'] = strFrom
    msg['Reply-to'] = strTo
    msg['To'] = strTo
    msg.preamble = 'This is a multi-part message in MIME format.'
    
    # Encapsulate the plain and HTML versions of the message body in an
    # 'alternative' part, so email agents can decide which they want to display.
    msgAlternative = MIMEMultipart('alternative')
    msg.attach(msgAlternative)
    msgText = MIMEText('''
Hello,

Paragraph of words

''')
    msgAlternative.attach(msgText)
    msgText = MIMEText('''<!DOCTYPE html>
<html lang="en">
<body> 

<p>
Hello,
</p><img src="cid:image1" alt=""/>

<p>
Paragraph of words
</p>

</body>
</html>

''', 'html')
    msgAlternative.attach(msgText)

    # Attach Any Images
    images = '''/Users/my/Desktop/logo.png'''.splitlines()
    I=1
    for image in images:
        # print 'Image',i,': ',image,'\n'
        fp = open(image, 'rb')
        msgImage = MIMEImage(fp.read())
        fp.close()
        # Define the image's ID as referenced above
        msgImage.add_header('Content-ID', '<image'+str(i)+'>')
        msg.attach(msgImage)
        I+=1

    # Attach any files
    files = '''/Users/my/Desktop/RKw.jpeg'''.splitlines()
    for file in files:
        attachment = open(file, "rb")
        part = MIMEBase("application", "octet-stream")
        part.set_payload((attachment).read())
        encoders.encode_base64(part)
        part.add_header("Content-Disposition", f"attachment; filename= {file.split('/')[-1].replace(' ','%20')}")
        msg.attach(part)     
                             
    #send the email
    smtp = smtplib.SMTP_SSL('''mail.SMTP.com''', '''465''') 
    smtp.ehlo() 
    smtp.login('''Me@My.com''', '''MyPassword''')
    smtp.sendmail(strFrom, strTo.split(","), msg.as_string())
    smtp.quit()
except: print("Sending Error : "+strTo)

You have I=1 and I+=1, but str(i).

Don’t use ‘bare’ excepts. Catch only those exceptions that you’re going to handle or ignore, not all of them. The bare except is catching a NameError due to a bug, namely, I vs i. That’s definitely not a “sending error”.

Also, there’s no point in importing modules that you’re not using, i.e., ss and mimetypes.

Thanks, that’s helpful, but perfectly illustrates what I know is part of my problem. I don’t know what I do need.

Re the I vs i, it seems to have been caused somehow when the Discuss software converted my post to pre-formatted text. Even now it keeps changing the lowercase to upper if I copy and paste it.

Forgive me but I’m on some medication which makes me a bit loopy.

Can you answer these questions for yourself?

  1. Are you using the most recent modules for sending email with attachments? Ask around to find out what those are. Microsoft recently (June 2023) turned off our POP and SMTP email servers permanently and now only supports another type of server which is more robust and secure, called IMAP.
  2. Are you using an IMAP server to send/receive email? POP and SMTP protocols are outdated and insecure. These are not the best for sending sensitive data.

The problem is definitely in my coding.

I am using an IMAP server and sending these emails using Python 2.7, everything works as it has for years. My update to using Python 3.9 is where it breaks.

As M Barnett suggested, there are some module imports that need to be corrected, and I do believe I’ve now gotten that accomplished. Still working on the script in its entirety though. My loops through the attachments aren’t fully up to date.