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) |