Last active
March 1, 2022 12:24
-
-
Save JustusAdam/e97d2c9d3fcdefbb8d12 to your computer and use it in GitHub Desktop.
Send a bunch of formatted emails using python templates and YAML/JSON data.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
""" | |
If you, like me, often have to send a bunch of very similer emails to a bunch of | |
people you may have got tired of copy pasting and resending as well. | |
This is my proposed solution: | |
This script reads a template file, using the simple python templating language | |
that substitutes vaules like $this with data from a dictionary. | |
The dictionary comes from a data file you provide. It can either be JSON or YAML | |
and the script will detect the type based on the file extension. | |
The data file has to contain the following: | |
- a 'credentials' key with 'host', 'user', 'password' and optionally a 'port' | |
for authentication with the smtp server. | |
- a 'values' key, containing a list of dicts/objects with keys for each substitution | |
one mail will be sent per item. | |
- a 'defaults' key containing default values which will be used should they be | |
absent in one of the objects from the values list | |
each item (values object + defaults) must contain at least a key called 'email', | |
containing which to send the email to. | |
Currenty the script just connects diretly, starts starttls and then authenticates | |
itself. You may change this to suite your needs by connecting wia SSH or removing | |
the starttls or the authentication entirely. | |
Usage: | |
./bulk_mail.py template datafile.yml | |
""" | |
from string import Template | |
import sys | |
import collections | |
import pathlib | |
import smtplib | |
from email.mime.text import MIMEText | |
def from_yaml(file): | |
import yaml | |
return yaml.load(file) | |
def from_json(file): | |
import json | |
return json.load(file) | |
loader = { | |
'yaml': from_yaml, | |
'yml': from_yaml, | |
'json': from_json | |
} | |
def format_mails(letter_template_raw, data): | |
has_def = 'defaults' in data and 'values' in data | |
if has_def: | |
defaults = data['defaults'] | |
values = data['values'] | |
else: | |
values = data | |
letter_template = Template(letter_template_raw) | |
def format_one(instance): | |
if has_def: | |
instance = collections.ChainMap(instance, defaults) | |
msg = MIMEText(letter_template.substitute(instance)) | |
msg['To'] = instance['email'] | |
msg['Subject'] = instance['subject'] | |
msg['From'] = instance['from'] | |
if 'cc' in instance: | |
msg['CC'] = instance['cc'] | |
return instance['email'], msg | |
return map(format_one, values) | |
def main(): | |
_, letter_file, data_file = sys.argv | |
with open(letter_file, 'r') as f: | |
letter = f.read() | |
with open(data_file) as f: | |
_, ext = data_file.rsplit('.', 1) | |
data = loader.get(ext, from_yaml)(f) | |
credentials = data['credentials'] | |
with smtplib.SMTP(credentials['host'], credentials.get('port', 0)) as smtp: | |
smtp.starttls() | |
smtp.login(credentials['user'], credentials['password']) | |
for address, msg in format_mails(letter, data): | |
smtp.send_message(msg) | |
print('Sent message to: ', address) | |
if __name__ == '__main__': | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment