
Like the Java Client Library, the Python Client Library provides a simple API to access Constant Contact Web Services, only using Python. Python is a powerful multi-platform language with comprehensive libraries, a interactive shell, and best of all, a short learning curve. This makes the Python Client Library a good choice for quickly creating utilities or applications that leverage Constant Contact’s APIs or for users looking to manage large accounts programmatically. Included in this post are links to the library itself and an overview of its usage with code examples to help you get started.
NOTE: This library is open source and is maintained and supported by the open source developer community only. Constant Contact and Constant Contact Labs will NOT provide support for this library.
https://sourceforge.net/projects/ctctwspylib/
Using the client library starts with creating a CTCTConnection object. You must supply a Constant Contact username and password as well as a Constant Contact developer key. If you don’t have an account you can create one here: And Constant Contact API keys are requested here:
API_KEY = "ctctabc-defghi-jklmnop" #not a valid key mConnection = CTCTConnection(API_KEY, "joe", "password123")
To authenticate credentials, in this case joe using password123, you might do the following:
isValid = mConnection.verify_credentials()
if(isValid):
#valid credentials
else:
#invalid credentials
Characters outside the character set a-zA-Z0-9.-_@ are not allowed in Constant Contact usernames. Using the library you are able to catch invalid usernames:
#make sure to import InvalidUsernameException
from __init__ import CTCTConnection, InvalidUsernameException
try:
isValid = mConnection.verify_credentials()
except InvalidUsernameException, err: #err contains an appropriate error message
print str(err)
Fields returned are:
Lists NOT returned:
#lists will contain a python list of dictionaries, each dictionary contains data for an individual list
lists = mConnection.get_contact_lists()
#print all the list names
for list in lists:
print list['name']
Lists are retrieved using the list id.
Fields returned are:
list_id = '123' list = mConnection.get_contact_list(list_id) #print the list name print list['name']
The list members are returned in a python list of dictionaries, each containing individual contact information.
Fields returned are:
list_id = '123'
#get the members of list 123
members = mConnection.get_contact_list_members(list_id)
#print the emails of all the members in list 123
for member in members:
print member['email_address']
To create a new list simply pass a list name.
#name of list to create name = 'My New List' #create the contact, wasCreated holds success wasCreated = mConnection.create_contact_list(name)
Update a list by passing the list id and a python dictionary containing the fields and values to update.
#list id to update
list_id = '123'
#specify parameters to change
params = {'name': 'New List Name'}
#update the list, wasUpdated holds succecss
wasUpdated = mConnection.update_contact_list(params, list_id)
To delete a list use the list id.
#list id to delete list_id = '123' #delete list 123, wasDeleted holds success wasDeleted = mConnection.delete_contact_list(list_id)
Fields returned are:
#retrieve all the contacts
contacts = mConnection.get_contacts()
#print the email addresses of all contacts
for contact in contacts:
print contact['email_address']
Retrieve detailed information about a contact by providing either a contact email address or a contact id. If both the contact id and email address are available use the id.
Fields returned are:
#get the contact by email
contact = mConnection.get_contact(email='joe@sampleaddress.com')
#get the contact by id
contact = mConnection.get_contact(contact_id_number='123')
#get the contact lists the contact is a member of
lists = contact['contact_lists']
#print all the lists ids the contact belongs to
for list_id in lists:
print list_id
To create a contact supply a dictionary of parameters, keys containting fields to add and corresponding values. Id will be created automatically so do not include it. At least one contact list for the contact to be added to is required.
#add the fields
params = {'email_address': 'joe@samplename.com', 'name': 'joe', 'home_phone': '9785554444', 'contact_lists': ['http://api.constantcontact.com/ws/customers/joe/lists/123']}
#create the contact and store success
wasCreated = mConnection.create_contact(params)
Updating an existing contact requires a dictionary of paramaters, fields to change with changed values, and the contact id or contact email address. Again, contact id is preferred.
#contact id to update
contact_id = '123'
#fields to update, note that new fields can also be added this way
params = {'name': 'joey', 'home_phone': '9783334545', 'city': 'New York'}
#update the contact using the contact id, and store success
wasUpdated = mConnection.update_contact(params, contact_id_number=contact_id)
#update the contact using an email address, ..
wasUpdated = mConnection.update_contact(params, email='joe@samplename.com')
To delete a contact all that is needed is the contact id or email address of the contact.
#contact id to delete contact_id = '123' #delete the contact using the contact id (preferred) wasDeleted = mConnection.delete_contact(contact_id_number=contact_id) #delete the contact using the email address wasDeleted = mConnection.delete_contact(email='joe@samplename.com')
To retrieve events for a contact specify the contact either by email address or contact id and the event type. Event type is an enumeration of the CTCTConnection class.
Event types are:
#get the number of bounce events for contact 123
bounce_events = mConnection.get_contact_events(event_type=CTCTConnection.EVENTS_BOUNCES, contact_id_number=123)
#get the number of opens for .(JavaScript must be enabled to view this email address)
open_events = mConnection.get_contact_events(event_type=CTCTConnection.EVENTS_OPENS, email='joe@samplename.com')
To retrieve all campaigns specify the type of campaigns to be returned. If no campaign type is specified, ALL will be returned. A python list of campaigns will be returned and each campaign in campaigns is a dictionary containing fields and values for each individual campaign.
Fields returned are:
Campaign type is an enumeration of the CTCTConnection class.
Campaign types are:
#get all sent campaigns
sent_campaigns = mConnection.get_campaigns(type=CTCTConnection.CAMPAIGNS_SENT)
#print the date for all sent campaigns
for campaign in sent_campaigns:
print campaign['date']
To retrieve an individual campaign just pass the campaign id. A dictionary containing the invidual campaign data will be returned.
Fields returned are:
campaign_id = '1234567890123'
#get the campaign by id
campaign = mConnection.get_campaign(campaign_id_number=campaign_id)
#print the campaign name
print 'The Campaign Name is ' + campaign['name']
#print the contact lists associated with the email campaign
lists = campaign['contact_lists']
for list in lists:
print list['id']
#print the campaign-included urls clicks tracking information
urls = campaign['urls']
for url in urls:
print url['clicks']
To retrieve events for a campaign specify the campaign id and the event type. Event type is an enumeration of the CTCTConnection class.
Event types are:
#get the bounce events for the campaign
bounce_events = mConnection.get_campaign_events('123456789123', CTCTConnection.EVENTS_BOUNCES)
#get the total sends for the campaign
sent = mConnection.get_campaign_events('12345678123', CTCTConnection.EVENTS_SENDS)
Fields returned are:
#get all activities
activities = mConnection.get_activities()
#print the status for all activities
for activity in activities:
print activity['status']
To retrieve an individual activity just pass the activity id. A dictionary containing the invidual activity data will be returned.
Fields returned are:
#not a real activity id, for example
activity_id = '1234567890123'
#get the individual activity
activity = mConnection.get_activity(activity_id_number=activity_id)
#print the errors for the activity if there are any
errors = activity['errors']
for error in errors:
print error
To create an Add or Remove Contacts activity you must supply a type (Add or Remove), the lists you would like to add to or remove from, and the actual contact data to be added or removed. The activity id is returned or None if it was unsuccessful
The types are: ADD_CONTACTS, SV_ADD, ADD_CONTACT_DETAIL, REMOVE_CONTACTS_FROM_LISTS. Constant Contact will decide which Add to use depending on the data so using any of the three add types will yield the same result. To remove contacts from lists use REMOVE_CONTACTS_FROM_LISTS.
The data has to be supplied in a tabular format. The first row is always the column names and each row after that is the data for each contact in the same order as the supplied columns. For example:
EMAIL ADDRESS, FIRST NAME, LAST NAME
.(JavaScript must be enabled to view this email address), Joe, Smith
.(JavaScript must be enabled to view this email address), Jane, Smith
...
In python, there is a dictionary containting a key columns and a key rows that contain the values in python lists. The lists will contain the column data and row data respectively.
#lists contacts will be added to
lists = ['http://api.constantcontact.com/ws/customers/username/lists/1', 'http://api.constantcontact.com/ws/customers/username/lists/2']
#data to be added to the lists, email address, first name
data = {'columns': ['EMAIL ADDRESS', 'FIRST NAME'], 'rows': ['num1@email.com', 'Joe']}
#create the add contact activity, the activity id is returned if successful
activity_id = mConnection.create_activity(type='SV_ADD', lists=lists, data=data)
#check the activity status
activity = mConnection.get_activity(activity_id_number=activity_id)
print activity['status']
A Clear Contacts activity is different than a Remove Contacts activity. It will clear all contacts from a list or lists. To create the activity just supply the lists to be cleared. The activity id is returned.
#lists to clear
lists = ['http://api.constantcontact.com/ws/customers/username/lists/1', 'http://api.constantcontact.com/ws/customers/username/lists/1']
#create clear contacts activity
activity_id = mConnection.create_activity(type='CLEAR_CONTACTS_FROM_LISTS', lists=lists)
#check the activity status
activity = mConnection.get_activity(activity_id_number=activity_id)
print activity['status']
A Export activity exports contacts from a list or lists to a txt or csv file. To create the activity just supply the type of EXPORT_CONTACTS and a list to export. Additionally you can also supply options which are passed in the ‘data’ parameter. Options are dictionary entries with the key being the keynames below and the corresponding value options.
Options (defaults are bold):
fileType (csv or txt)
exportOptDate (true or false)
exportOptSource (true or false)
exportListName (true or false)
sortBy (EMAIL_ADDRESS, DATE_DESC)
columns (FIRST NAME, MIDDLE NAME, LAST NAME, etc…
complete list see http://developer.constantcontact.com/doc/activities)
#the list to export
lists = {'list_id': 'http://api.constantcontact.com/ws/customers/username/lists/1'}
#the columns to export, email address is always exported by default
data = {'columns': ['First Name', 'Last Name']}
#create an export activity as a csv file sorting the columns by date descending
activity_id = mConnection.create_activity(type='EXPORT_CONTACTS', lists=lists, data=data)
#check the activity status
activity = mConnection.get_activity(activity_id_number=activity_id)
print activity['status']
* Please be aware that all comments are moderated.
Disappointing to see there’s no Android App to support my account…you guys could loose a customer here!
Happy Christmas
Elf M. Sternberg | 2:54 PM January 19, 2010
Hey, Huan, I’ve been trying to use the library, and it’s a mess. The get_contact_list_members is looking for a string that’s not returned in the atom retreived, and while all my addresses through my login at constant contract are valid, I’m getting a lot of None values for email addresses.
Is there any initiative to update the ctctwspylib.py library to match the output of your ws anytime soon?
Huan Lai | 1:23 PM January 20, 2010
Hello there Elf,
Do you mind posting the code that you used? I just did a quick test of the code from SourceForge and it seemed to work fine. Perhaps there is a bug that we missed, or the documentation is lacking.
Thank you,
Huan Lai
Brendan White | 2:22 PM January 20, 2010
Elf,
After testing on multiple accounts we haven’t run into any problems using that particular function. To get through the problem you are having it’s best to submit a bug to the library on SourceForge.net. It will be easier for you to provide more information (including files) using that system than our comments section, and your bug (if it is a bug) may be fixed sooner if it is available to the open-source community.
Submitting A Bug:
1. Navigate to: http://sourceforge.net/projects/ctctwspylib/support
2. Click on the link “Bugs” toward the bottom of the page under “Project Trackers”
3. Toward the top of the page find the link titled “Add new” and click it
4. Add as much information regarding the bug and upload any helpful files
5. Click “Add artifact” to submit the bug
Also, at this time there is no plan to update the library to match the output of the CTCT WebServices.
David | 7:56 PM February 17, 2010
Are there plans to add support to create campaigns via the python client lib?
Brendan White | 6:11 PM February 18, 2010
Hi David,
Thanks for the comment. Eventually we would like to support all our web services functionality in the library, but at this time there is no formal plan for the Labs to add support for creating campaigns via the Python Client Library. That being said we are not the only contributors to the library. There is always the chance a developer from the open source community will add that support before we do.
The best thing to do is add a feature request to the project page so that other contributing developers can view your request. To post a feature request follow the link in step 1 of “Submitting A Bug” in the comment above, Click “Feature Requests” toward the bottom of the page under “Project Trackers”, and then follow steps 3 - 5 to submit.
Oleg K | 2:10 PM September 17, 2010
there is a bug at line 800 in __init__.py “campaigns.extend(self.get_campaigns(next_path))”
should be
“campaigns.extend(self.get_campaigns(path=next_path))”
otherwise it will request same page ower and ower again, instead next page
Collin Anderson | 5:17 PM December 2, 2010
I submitted a bug. http://sourceforge.net/tracker/?func=detail&aid=3125968&group_id=291725&atid=1233429
Mobley Hobbs | 5:52 PM April 7, 2011
Get Your Spring Carpet Clean Today.