Skip to content

Instantly share code, notes, and snippets.

@anemitz
Created August 24, 2013 00:07
Show Gist options
  • Save anemitz/6325147 to your computer and use it in GitHub Desktop.
Save anemitz/6325147 to your computer and use it in GitHub Desktop.
Send drip-style email through Close.io's API
#!/usr/bin/env python
import sys
import time
import codecs
import argparse
from pybars import Compiler
from closeio_api_client.api import CloseIO_API as CloseIO
sys.stdout = codecs.getwriter('utf8')(sys.stdout)
# We ensure the same templateid doesn't get sent again (see the search query construction)
emails = {
#'Label': ('Search Query', 'Close.io template_id')
}
parser = argparse.ArgumentParser(description='Send some drip emails.')
parser.add_argument('--api_key', required=True, help='Close.io Api Key')
parser.add_argument('--prod', type=bool, default=False, help='Connect to production?')
parser.add_argument('--send', type=bool, default=False, help='Actually send the emails?')
args = parser.parse_args()
client = CloseIO(args.api_key, development=not args.prod)
api_key = client.get('api_key/%s' % args.api_key)
organization_id = api_key['organization_id']
user_id = api_key['user_id']
user = client.get('me')
compiler = Compiler()
for label, drip in emails.items():
query = drip[0]
template_id = drip[1]
print ':::: %s :::: %s ::::' % (label, query)
template = client.get('email_template/%s' % template_id)
template_subject = compiler.compile(template['subject'])
template_body = compiler.compile(template['body'])
#print "(DEBUG) template:", template
has_more = True
offset = 0
while has_more:
search_query = "%s and not email_template:%s and has:email_address" % (query, template['id'])
print "*** QUERY ***", search_query
resp = client.get('lead', data={'_skip': offset, 'query': search_query, '_fields': 'id,name,contacts'})
print "*** TOTAL RESULTS ***", resp['total_results']
data = resp['data']
for lead in data:
print "\tLead: ", lead['name']
contact = lead['contacts'][0] if lead['contacts'] else {}
if not contact:
print "\t\tSkipping: Lead has no contact"
continue
if not contact['emails']:
print "\t\tSkipping: Contact has no email"
continue
email_address = contact['emails'][0]['email']
if contact.get('name'):
contact['first_name'] = contact.get('name', '').split()[0].capitalize()
print "\t\tContact: %s (%s)" % (contact['name'], email_address)
context = {'lead': lead, 'user': user, 'contact': contact}
email_subject = ''.join(template_subject(context))
email_body = ''.join(template_body(context))
email = {
'contact_id': contact['id'],
'user_id': user['id'],
'lead_id': lead['id'],
'to': [email_address],
'subject': email_subject,
'body_text': email_body,
'status': 'outbox',
'template_id': template['id']
}
if args.send:
print "\t\t(DEBUG) response:\n", client.post('activity/email', email)
# stupidly make sure search index gets updated...
# and stupidly try and not get google to throttle us...
time.sleep(5)
print "\n"
offset += len(data)
has_more = resp['has_more']
@philfreo
Copy link

philfreo commented Sep 5, 2013

With this approach, note that there will be a slight different in the template variable parsing -- for example a tag like {{contact.first_name}} is normally generated by the JavaScript in our application and therefore shouldn't appear in your template if you're parsing the templates yourself. Basically.... if you're using this method be sure to check the parsed templates to make sure they are doing what you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment