Skip to content

Instantly share code, notes, and snippets.

@nloadholtes
Created February 25, 2018 20:35
Show Gist options
  • Save nloadholtes/253fe1673b006dffda5847a83ed22fab to your computer and use it in GitHub Desktop.
Save nloadholtes/253fe1673b006dffda5847a83ed22fab to your computer and use it in GitHub Desktop.
The script I am using to generate daily emails for my Stoic Inspiration mailing list.
from mailchimp3 import MailChimp
import os
import sys
import datetime
import gspread
from oauth2client.service_account import ServiceAccountCredentials
import random
from functools import partial
import json
USERNAME = os.environ.get("MC_USERNAME", "")
SECRET_KEY = os.environ.get("MC_SECRET_KEY", "")
client = MailChimp(USERNAME, SECRET_KEY)
# Quote sheet for testing:
# https://docs.google.com/spreadsheets/d/126_iTXN0eQQSW9w8tUCcVBgQU9-7XPiRybOKpS5ZUKc/edit#gid=0
scope = ['https://spreadsheets.google.com/feeds']
credentials = ServiceAccountCredentials.from_json_keyfile_name(os.environ.get("GOOGLE_CREDS"), scope)
def get_quotes(qty, start_date):
"""Get a list of <qty> items from the spreadsheet"""
gc = gspread.authorize(credentials)
sh = gc.open_by_key(YOUR-SPREADSHEET-ID-GOES-HERE)
quotes = sh.get_worksheet(0)
results = _list_recent_quotes(quotes.get_all_records(), qty)
_update_quotes_date_used(quotes, results, start_date)
return results
def _filter_by_date(older_than, quote):
"""Check each quote to see if is eligable"""
if "date_used" in quote:
try:
result = datetime.datetime.strptime(quote["date_used"], "%m/%d/%Y") < older_than
return result
except:
print("Bad quote date: %s" % quote)
return False
def _list_recent_quotes(quotes, qty, older_than=90):
"""Return a list of <qty> that are older than <older_than> days """
today = datetime.datetime.now()
max_age = today - datetime.timedelta(days=older_than)
candidates = filter(partial(_filter_by_date, max_age), quotes)
return random.sample(list(candidates), qty)
def _update_quotes_date_used(quotes, selected_quotes, start_date):
"""Update the worksheet to make sure the quotes are using are marked
as being used. Also, update the date_used in the quotes themselves."""
for day_count, quote in enumerate(selected_quotes):
cell_row = quotes.findall(r'%s' % quote["quote_id"])[0].row
updated_value = start_date + datetime.timedelta(days=day_count)
formatted_date = datetime.datetime.strftime(updated_value, "%m/%d/%Y")
quotes.update_cell(cell_row,
2,
formatted_date)
quote["date_used"] = formatted_date
def get_list_id(list_name):
"""Get the id for a given list name"""
lists = client.lists.all()
for l in lists.get("lists", []):
if l.get("name", "") == list_name:
return l.get("id")
def create_campaign(campaign_data):
"""
Create a campaign
"""
camp = client.campaigns.create(campaign_data)
# print(camp)
return camp
def populate_campagin_data(list_id, author, quote, date, auto_tweet=False):
campaign_data = {"settings": {"title": "S.I. %s" % date,
"subject_line": "Today's Stoic Inspiration from %s" % author,
"from_name": A-NAME-FOR-THE-FROM-TEXT,
"reply_to": YOUR-EMAIL-ADDRESS-HERE,
"auto_tweet": auto_tweet
},
"recipients": {"list_id": list_id},
"type": "regular"}
return campaign_data
def populate_content(campaign_id, quote, author):
"""
Put the content of the email into the campaign
:param campaign: The struct genereated by :create_campaign:
:param quote:
:return:
"""
data = { "html": _htmlized(quote, author),
"plain_text": "\n\n%s\n\n-%s" % (quote, author)}
result = client.campaigns.content.update(campaign_id=campaign_id, data=data)
print("\n\nResult:")
print(result)
return result
def _htmlized(quote, author):
"""
Let's keep this abomination private
:param quote:
:param author:
:return:
"""
html = """<!doctype html><html><h1 style="color: #202020;font-family: Helvetica;font-size: 26px;font-style: normal;">%s</h1>
<br><h1 style="color: #202020;font-family: Helvetica;font-size: 26px;font-style: normal;">&mdash;%s</h1></html>""" % (quote, author)
return html
if __name__ == "__main__":
list_name = "Stoic emails"
if len(sys.argv) == 2:
start_date = datetime.datetime.strptime(sys.argv[1], '%m/%d/%Y')
data = get_quotes(5, start_date)
# Save the quotes so I can feed them back in if needed
with open("blah.json", "w") as f:
f.write(json.dumps(data))
else:
data = json.load(open("blah.json", "r"))
# Start
list_id = get_list_id(list_name)
for day in data:
campaign_data = populate_campagin_data(list_id, day["author"], day["quote"], day["date_used"])
camp = create_campaign(campaign_data)
populate_content(camp["id"], day["quote"], day["author"])
when_to_send = datetime.datetime.strptime(day["date_used"] + " 10:00", "%m/%d/%Y %H:%M").replace(tzinfo=datetime.timezone.utc)
client.campaigns.actions.schedule(
camp["id"],
{"schedule_time": when_to_send})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment