Skip to content

Instantly share code, notes, and snippets.

@queensferryme queensferryme/
Last active Feb 8, 2019

What would you like to do?
Email automatic templating & sending implemented with Python
#!/usr/bin/env python
from csv import DictReader
from email.encoders import encode_base64
from email.header import Header
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 os.path import split, splitext
from smtplib import SMTP, SMTPException
from ssl import create_default_context
class EmailSender:
def __init__(self, config):
'''initialize an email sender'''
self.cli = SMTP(config['host'], config['port'])
self.config = config
if type(self.config['data']) is str:
with open(self.config['data'], 'rt', encoding='utf-8') as file:
data = list(DictReader(file))
self.config['data'] = data
def login(self):
'''log into remote smtp server'''
self.cli.login(self.config['user'], self.config['passwd'])
except SMTPException:
print('ERROR: smtp server login failed')
print('INFO: smtp server login success')
def logout(self):
'''close the connection to remote smtp server'''
def send(self):
'''send mails based on user\'s configuration'''
for index, receiver in enumerate(self.config['receivers']):
self.cli.sendmail(self.config['sender'], receiver, self._message(index).as_string())
except SMTPException:
print('ERROR: email failed to send to {}'.format(receiver))
print('INFO: email successfully sent to {}'.format(receiver))
def _message(self, index):
'''create an email message object with given index of current receiver'''
data = self.config['data'][index] if self.config['data'] else {}
# create a multi-part message
message = MIMEMultipart()
message['From'] = Header(self.config['sender'], 'utf-8')
message['To'] = Header(self.config['receivers'][index], 'utf-8')
message['Subject'] = Header(self.config['message']['subject'].format(**data), 'utf-8')
# add main context
message.attach(MIMEText(self.config['message']['template'].format(**data), 'html', 'utf-8'))
# add attachments
for filename in self.config['message']['attachments']:
attachment = MIMEBase('application', 'octet-stream')
attachment.add_header('Content-Disposition', 'attachment;filename={}'.format(split(filename)[-1]))
with open(filename, 'rb') as file:
# add images
for key, filename in self.config['message']['images'].items():
with open(filename, 'rb') as file:
image = MIMEImage(, _subtype=splitext(filename)[-1].replace('.', ''))
image.add_header('Content-ID', key)
return message
if __name__ == '__main__':
mailer = EmailSender({
'host': '',
'port': 25,
'user': '',
'passwd': 'your-pass-word',
'sender': '',
'receivers': [
'data': 'guests.csv',
'message': {
'subject': 'invitation for {name} at {addr}',
'template': '''
<p>we sincerely invite you to join our party.</p>
<p>your entrance id is <code>{id}</code>.</p>
<img src="cid:img" alt="invitation-card">
'attachments': [
'images': {
'img': 'invitation.jpg'

This comment has been minimized.

Copy link
Owner Author

queensferryme commented Jan 18, 2019

guests.csv should look like this:

name addr id
John New York 0021
Mako California 1988
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.