pip install pandas Jinja2 tqdm
$ python3 secret_santa.py
Google Sheet Structure needs to have the following columns [Nom, Prenom, Email]
pip install pandas Jinja2 tqdm
$ python3 secret_santa.py
Google Sheet Structure needs to have the following columns [Nom, Prenom, Email]
import argparse | |
import json | |
import random | |
from datetime import date | |
from email.mime.multipart import MIMEMultipart | |
from email.mime.text import MIMEText | |
from smtplib import SMTP | |
from typing import Dict | |
import pandas as pd | |
from jinja2 import Template | |
from tqdm import tqdm | |
# Keep Pairs in backup.json in case issue with email happens | |
KEEP_BACKUP: bool = True | |
# run matchmaking without sending emails | |
TEST: bool = False | |
EMAIL_TEMPLATE = """ | |
<p> | |
Hello <b>{{full_name}}</b> and welcome to the CoML secret santa {{year}} edition. | |
</p> | |
<p> You have to buy a gift for <b>{{target_name}}</b>. </p> | |
<p> The budget limit is {{budget}}€. </p> | |
""" | |
SUBJECT = 'CoML Secret Santa' | |
cfg = argparse.Namespace(**{ | |
"sheet_id": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", | |
"sheet_name": "secret-santa", | |
"budget": 10, | |
"from_email": "email@addrr", | |
"smtp_server": "smtp.com", | |
"smtp_port": 587, | |
"smtp_username": "email@addrr", | |
"smtp_password": "passwd" | |
}) | |
def build_email_body(person: Dict, budget: int): | |
""" Build email from template and person """ | |
tm = Template(EMAIL_TEMPLATE) | |
return tm.render( | |
full_name=f"{person['Nom'].title()} {person['Prenom'].title()}", | |
year=f"{date.today().year}", | |
target_name=f"{person['gift_to']['Nom'].title()} {person['gift_to']['Prenom'].title()}", | |
budget=budget | |
) | |
def load_csv(sheet_id: str, sheet_name: str): | |
""" Load a google sheet """ | |
url = f"https://docs.google.com/spreadsheets/d/{sheet_id}/gviz/tq?tqx=out:csv&sheet={sheet_name}" | |
return pd.read_csv(url) | |
def send_mail(email_cfg: argparse.Namespace, to_email: str, subject: str, body: str): | |
""" Function to send an email """ | |
message = MIMEMultipart() | |
message['Subject'] = subject | |
message['From'] = email_cfg.from_email | |
message['To'] = to_email | |
message.attach(MIMEText(body, "html")) | |
msg_body = message.as_string() | |
# connect to smtp | |
server = SMTP(email_cfg.smtp_server, email_cfg.smtp_port) | |
server.starttls() | |
server.login(email_cfg.smtp_username, email_cfg.smtp_password) | |
# send email | |
server.sendmail(email_cfg.from_email, to_email, msg_body) | |
server.quit() | |
def make_pairs(data: pd.DataFrame): | |
""" Match each person in Dataframe with a random unique other person""" | |
givers = data.to_dict(orient="records") | |
takers = data.to_dict(orient="records") | |
for gv in givers: | |
choice = random.randrange(len(takers)) | |
while gv["Email"] == takers[choice]['Email']: | |
choice = random.randrange(len(takers)) | |
gv["gift_to"] = takers.pop(choice) | |
return givers | |
if __name__ == '__main__': | |
# load emails from google | |
df = load_csv(cfg.sheet_id, cfg.sheet_name) | |
# match people into pairs | |
people = make_pairs(df) | |
# backup people in case of issue | |
if KEEP_BACKUP: | |
with open('backup.log.json', 'w') as fp: | |
json.dump(people, fp) | |
# loop over people & send emails | |
for p in tqdm(people): | |
email_body = build_email_body(p, cfg.budget) | |
if TEST: | |
print(f'{p["Nom"]} {p["Prenom"]} --> {p["gift_to"]["Nom"]} {p["gift_to"]["Prenom"]}') | |
else: | |
send_mail(cfg, p['Email'], SUBJECT, email_body) |