Skip to content

Instantly share code, notes, and snippets.

@loleg

loleg/santa.py

Forked from will-bainbridge/santa.py
Created Dec 6, 2020
Embed
What would you like to do?
Secret Santa script
#!/usr/bin/python3
"""
Ye olde Secret Santa script based on https://gist.github.com/will-bainbridge/a4666a196fb5833cf37035647b74c064
You will need to prepare a "people file", which is in CSV format (UTF-8, comma delimited) and has the following columns (without a header row)
Name, E-mail, Extra content 1, Extra content 2
We used the postal address as extra content 1 and a link to Google Street View as extra content 2. Then you can specify a plain text message file which includes %s for the buyer name, recipient name, recipient extra 1, and recipient extra 2 (in that order!). For example:
Ho ho ho! Merry Christmas dear %s
You are the secret santa of %s
Please send joyful greetings to %s
To make a virtual visit go to %s
Example test run command (remove --no-send to actually send it):
python3 santa.py --people-file=family.csv \
--message-from=santyklaus@northpole.ch \
--message-subject="A global family x-mas" \
--message-body-file=message.txt \
--server-address=mail.northpole.ch \
--server-port=25 \
--server-user=santyklaus@northpole.ch \
--no-send
Note: the script requires Python 3 and numpy installed on your system.
"""
import csv
import getpass
import numpy as np
import optparse
import smtplib
import sys
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
parser = optparse.OptionParser()
parser.add_option(
'--people-file',
help='the CSV file (see details in script) of each person included in the secret santa',
metavar='FILE'
)
parser.add_option(
'--no-message',
action='store_true',
help='don\'t construct or send the messages, just print the matches',
)
parser.add_option(
'--no-send',
action='store_true',
help='don\'t send the messages, just print the messages',
)
parser.add_option(
'--message-from',
help='the email address the message is from',
metavar='EMAIL'
)
parser.add_option(
'--message-subject',
help='the message subject line',
metavar='SUBJECT'
)
parser.add_option(
'--message-body-file',
help='the file containing the message body (see instructions in script)',
metavar='FILE'
)
parser.add_option(
'--server-address',
help='the SMTP server address',
metavar='ADDRESS'
)
parser.add_option(
'--server-port',
help='the SMTP server port',
metavar='PORT'
)
parser.add_option(
'--server-user',
help='the SMTP server user',
metavar='USER'
)
options, dummy = parser.parse_args()
# Check options
if options.people_file is None:
parser.error('people-file not given')
if not options.no_message:
if options.message_from is None:
parser.error('message-from not given')
if options.message_subject is None:
parser.error('message-subject not given')
if options.message_body_file is None:
parser.error('message-body-file not given')
if not (options.no_send or options.no_message):
if options.server_address is None:
parser.error('server-address not given')
if options.server_port is None:
parser.error('server-port not given')
if options.server_user is None:
parser.error('server-user not given')
with open(options.people_file) as peopleFile:
people = [ tuple(row) for row in csv.reader(peopleFile, delimiter=',', quotechar='"') ]
if not options.no_message:
with open(options.message_body_file) as messageBodyFile:
messageBody = ''.join(messageBodyFile.readlines())
if not (options.no_send or options.no_message):
passwordPrompt = 'Password for %s@%s: ' % (options.server_user, options.server_address)
server = smtplib.SMTP(options.server_address, options.server_port)
server.ehlo()
server.starttls()
server.ehlo()
server.login(options.server_user, getpass.getpass(passwordPrompt))
while True:
permutation = np.random.permutation(len(people))
if not any([
people[b][2] == people[r][2] for b, r in
zip(permutation, np.roll(permutation, 1))
]):
break
for b, r in zip(permutation, np.roll(permutation, 1)):
buyer, recipient = people[b], people[r]
if not options.no_message:
msg = MIMEMultipart()
msg['From'] = options.message_from
msg['To'] = buyer[1]
msg['Subject'] = options.message_subject
body = messageBody % (buyer[0], recipient[0], recipient[2], recipient[3])
msg.attach(MIMEText(body, 'plain'))
if options.no_message:
print(buyer[0], "buys for", recipient[0])
elif options.no_send:
print(msg)
else:
server.sendmail(msg['from'], msg['to'], msg.as_string())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment