Reliable SMTP email delivery

Due to issues with the Email Service configured with a custom SMTP server passing configuration tests, sending test emails from code successfully, and then randomly breaking, I’ve created my own SMTP email function, which works flawlessly in a Python 3 Full environment, but fails with the following error in a Python 2 Full environment:

ImportError: No module named utils

[Try selecting a different Python version.]

at /usr/local/lib/python2.7/smtplib.py, line 46

Occurring at this line:

import smtplib

in the following code:

def send_smtp_email(mail_from, mail_to, mail_subject, mail_txt, mail_html=None, cc_sender=False):
  if cc_sender is True:
    mail_cc = mail_from
  else:
    mail_cc = None

  # Depends on a valid App Secret value in the SMTP_PASSWORD secret
  SMTP_PASSWORD = anvil.secrets.get_secret('SMTP_PASSWORD')

  settings = {
    'server': '[redacted]',
    'port': 587,
    'username': '[redacted]'
  }
  
  import smtplib
  from email.mime.multipart import MIMEMultipart
  from email.mime.text import MIMEText
  from email.message import EmailMessage

  # Establish SMTP Connection
  server = smtplib.SMTP(settings['server'], settings['port']) 

  # Start TLS based SMTP Session
  server.starttls() 

  # Login Using Your Email ID & Password
  server.login(settings['username'], SMTP_PASSWORD)

  # Create Email Message in Proper Format
  msg = EmailMessage()
  msg.set_charset("utf-8")

  # Setting Email Parameters
  msg['From'] = mail_from
  msg['To'] = mail_to
  msg['Subject'] = mail_subject
  
  if mail_cc not in ('', None):
    msg['CC'] = mail_cc
  
  # Add Message To Email Body
  msg.set_content(mail_txt)
  
  # Add HTML Message To Email Body
  if mail_html not in ('', None):
    msg.add_alternative(mail_html, subtype='html')
    
  # Send the Email
  try:
    server.send_message(msg)
  except Exception as e:
    print("Error: unable to send email: {}".format(repr(e)))
    
  # Terminating the SMTP Session
  server.quit()

It would seem to me that this is an issue in the libraries available in the Python 2 Full environment. Is there something obvious I could be missing?

Hi @splinter,

A quick google of the error takes me to this post which I believe might answer your question. This would certainly explain why it only breaks in Python 2, where the import rules are different.

Do you have a module called email in your code somewhere?

That definitely helped, I have a server module named ‘email’, renamed it to emails and it got a little further in the code, new error is:

ImportError: cannot import name EmailMessage

[Try selecting a different Python version.]

at [emails, line 817] called from [emails, line 163] called from [Tournament, line 546]

So, the namespace issue with having a server module with the same name as a python library was definitely triggering on

from email.mime.multipart import MIMEMultipart

even though the error was pointing at the import smtplib line

at this point, looks like there’s another package issue further in, triggered by

from email.message import EmailMessage

Got it working with some edits for python 2.7 from https://docs.python.org/2/library/email-examples.html

def send_smtp_email(mail_from, mail_to, mail_subject, mail_txt, mail_html=None, cc_sender=False):
  if cc_sender is True:
    mail_cc = mail_from
  else:
    mail_cc = None

  # Depends on a valid App Secret value in the SMTP_PASSWORD secret
  SMTP_PASSWORD = anvil.secrets.get_secret('SMTP_PASSWORD')

  settings = {
    'server': '[redacted]',
    'port': 587,
    'username': '[redacted]'
  }
  
  import smtplib
  from email.mime.multipart import MIMEMultipart
  from email.mime.text import MIMEText

  # Establish SMTP Connection
  server = smtplib.SMTP(settings['server'], settings['port']) 

  # Start TLS based SMTP Session
  server.starttls() 

  # Login Using Your Email ID & Password
  server.login(settings['username'], SMTP_PASSWORD)

  # Create Email Message in Proper Format
  msg = MIMEMultipart('alternative')
  msg.set_charset("utf-8")

  # Setting Email Parameters
  msg['From'] = mail_from
  msg['To'] = mail_to
  msg['Subject'] = mail_subject.encode('utf-8')
  
  if mail_cc not in ('', None):
    msg['CC'] = mail_cc
  
  # Add Message To Email Body
  part1 = MIMEText(mail_txt.encode('utf-8'), 'plain')
  msg.attach(part1)
  
  # Add HTML Message To Email Body
  if mail_html not in ('', None):
    part2 = MIMEText(mail_html.encode('utf-8'), 'html')
    msg.attach(part2)
    
  # Send the Email
  try:
    server.sendmail(mail_from, [mail_to, mail_cc], msg.as_string())
  except Exception as e:
    print("Error: unable to send email: {}".format(repr(e)))
    
  # Terminating the SMTP Session
  server.quit()

Thank you, @bridget!

1 Like