Gibbon is an API wrapper for MailChimp's API
Gibbon is an API wrapper for MailChimp's API.
Please read MailChimp's Getting Started Guide.
Gibbon returns a Gibbon::Response, which exposes the parsed response body and the response headers. See Responses below.
See the CHANGELOG for release history and Upgrading for breaking changes.
$ gem install gibbonOr add it to your Gemfile:
gem "gibbon"Gibbon depends on Faraday (both 1.x and 2.x are supported) and MultiJson. Connections to MailChimp negotiate TLS 1.2 or newer.
First, create a one-time use instance of Gibbon::Request:
gibbon = Gibbon::Request.new(api_key: "your_api_key")Note Only reuse instances of Gibbon after terminating a call with a verb, which makes a request. Requests are light weight objects that update an internal path based on your call chain. When you terminate a call chain with a verb, a request instance makes a request and resets the path. See How call chains build paths.
You can set an individual request's timeout and open_timeout like this:
gibbon.timeout = 30
gibbon.open_timeout = 30You can read about timeout and open_timeout in the Net::HTTP doc.
Now you can make requests using the resources defined in MailChimp's docs. Resource IDs
are specified inline and a CRUD (create, retrieve (or get), update, upsert, or delete) verb initiates the request. upsert lets you update a record, if it exists, or insert it otherwise where supported by MailChimp's API.
Each verb maps to an HTTP method:
| Gibbon verb | HTTP method | Accepts body |
|---|---|---|
create |
POST |
yes |
retrieve (or get) |
GET |
no |
update |
PATCH |
yes |
upsert |
PUT |
yes |
delete |
DELETE |
no |
You can specify headers, params, and body when calling a CRUD method. For example:
gibbon.lists.retrieve(headers: {"SomeHeader": "SomeHeaderValue"}, params: {"query_param": "query_param_value"})Of course, body is only supported on create, update, and upsert calls. Those map to HTTP POST, PATCH, and PUT verbs respectively.
You can set api_key, timeout, open_timeout, faraday_adapter, proxy, symbolize_keys, logger, and debug globally:
Gibbon::Request.api_key = "your_api_key"
Gibbon::Request.timeout = 15
Gibbon::Request.open_timeout = 15
Gibbon::Request.symbolize_keys = true
Gibbon::Request.debug = falseFor example, you could set the values above in an initializer file in your Rails app (e.g. your_app/config/initializers/gibbon.rb).
Assuming you've set an api_key on Gibbon, you can conveniently make API calls on the class itself:
Gibbon::Request.lists.retrieveYou can also set the environment variable MAILCHIMP_API_KEY and Gibbon will use it when you create an instance:
gibbon = Gibbon::Request.newPass symbolize_keys: true to use symbols (instead of strings) as hash keys in API responses.
gibbon = Gibbon::Request.new(api_key: "your_api_key", symbolize_keys: true)MailChimp's resource documentation is a list of available resources.
Gibbon::Request defines no methods for MailChimp's resources. Any unknown method appends a segment to an internal path and returns the same object; a CRUD verb turns the accumulated path into a request. So gibbon.lists(list_id).members.retrieve builds lists//members and issues a GET.
Three consequences are worth knowing.
Underscores become hyphens. Segments containing a hyphen aren't valid Ruby method names, so write them with underscores and Gibbon converts:
gibbon.lists(list_id).members(subscriber_hash).actions.delete_permanent.create
# POST lists//members//actions/delete-permanentsend is special cased. Object#send would otherwise shadow the path segment, so Gibbon::Request#send falls through to path building when called with no arguments. That's what makes sending a campaign work:
gibbon.campaigns(campaign_id).actions.send.create
# POST campaigns//actions/sendCalled with arguments, send keeps its usual Ruby meaning and invokes the named method.
An instance is reusable only after a verb. The path resets when a verb runs, not when a chain goes out of scope. Abandoning a chain leaves its segments in place and corrupts the next call:
gibbon = Gibbon::Request.new(api_key: "your_api_key")
gibbon.lists # no verb, so nothing is sent and nothing is reset
gibbon.campaigns.retrieve # GET lists/campaigns -- not what you wantedUse a fresh instance per chain unless you know the previous one ended in a verb.
Every CRUD verb returns a Gibbon::Response with two attributes:
body — the parsed JSON response, as a Hash (or Array, depending on the endpoint)headers — the response headers, keyed by lower case stringresponse = gibbon.lists.retrieve
response.body["lists"] # => [{"id" => "...", "name" => "...", ...}, ...]
response.headers["content-type"] # => "application/json; charset=utf-8"body respects symbolize_keys; headers keys are always strings.
A response with an empty body — as with a successful delete, which MailChimp answers with 204 No Content — returns nil rather than a Gibbon::Response.
Pass debug: true to enable debug logging to STDOUT.
gibbon = Gibbon::Request.new(api_key: "your_api_key", debug: true)Ruby Logger.new is used by default, but it can be overridden using:
gibbon = Gibbon::Request.new(api_key: "your_api_key", debug: true, logger: MyLogger.new)Logger can be also set by globally:
Gibbon::Request.logger = MyLogger.newFetch first page of lists:
gibbon.lists.retrieveRetrieving a specific list looks like:
gibbon.lists(list_id).retrieveRetrieving a specific list's members looks like:
gibbon.lists(list_id).members.retrieveGet first page of subscribers for a list:
gibbon.lists(list_id).members.retrieveBy default the Mailchimp API returns 10 results. To set the count to 50:
gibbon.lists(list_id).members.retrieve(params: {"count": "50"})And to retrieve the next 50 members:
gibbon.lists(list_id).members.retrieve(params: {"count": "50", "offset": "50"})And to retrieve only subscribed members
gibbon.lists(list_id).members.retrieve(params: {"count": "50", "offset": "50", "status": "subscribed"})Subscribe a member to a list:
gibbon.lists(list_id).members.create(body: {email_address: "[email protected]", status: "subscribed", merge_fields: {FNAME: "First Name", LNAME: "Last Name"}})If you want to upsert instead, you would do the following:
gibbon.lists(list_id).members(lower_case_md5_hashed_email_address).upsert(body: {email_address: "[email protected]", status: "subscribed", merge_fields: {FNAME: "First Name", LNAME: "Last Name"}})You can also unsubscribe a member from a list:
gibbon.lists(list_id).members(lower_case_md5_hashed_email_address).update(body: { status: "unsubscribed" })Get a specific member's information (open/click rates etc.) from MailChimp:
gibbon.lists(list_id).members(lower_case_md5_hashed_email_address).retrievePermanently delete a specific member from a list:
gibbon.lists(list_id).members(lower_case_md5_hashed_email_address).actions.delete_permanent.createTags are a flexible way to organize (slice and dice) your list: for example, you can send a campaign directly to one or more tags.
Add tags to a subscriber:
gibbon.lists(list_id).members(Digest::MD5.hexdigest(lower_case_email_address)).tags.create(
body: {
tags: [{name:"referred-from-xyz", status:"active"},{name:"pro-plan",status:"active"}]
}
)Any API call that can be made directly can also be organized into batch operations. Performing batch operations requires you to generate a hash for each individual API call and pass them as an Array to the Batch endpoint.
# Create a new batch job that will create new list members
gibbon.batches.create(body: {
operations: [
{
method: "POST",
path: "lists/#{ list_id }/members",
body: "{...}" # The JSON payload for PUT, POST, or PATCH
},
...
]
})This will create a new batch job and return a Batch response. The response will include an id attribute which can be used to check the status of a particular batch job.
gibbon.batches(batch_id).retrieveresponse.body){
"id"=>"0ca62e43cc",
"status"=>"started",
"total_operations"=>1,
"finished_operations"=>1,
"errored_operations"=>0,
"submitted_at"=>"2016-04-19T01:16:58+00:00",
"completed_at"=>"",
"response_body_url"=>""
}Note This response truncated for brevity. Reference the MailChimp API documentation for Batch Operations for more details.
Only retrieve ids and names for fetched lists:
gibbon.lists.retrieve(params: {"fields": "lists.id,lists.name"})Only retrieve emails for fetched lists:
gibbon.lists(list_id).members.retrieve(params: {"fields": "members.email_address"})Get first page of campaigns:
campaigns = gibbon.campaigns.retrieveFetch the number of opens for a campaign
email_stats = gibbon.reports(campaign_id).retrieve.body["opens"]Create a new campaign:
recipients = {
list_id: list_id,
segment_opts: {
saved_segment_id: segment_id
}
}
settings = {
subject_line: "Subject Line",
title: "Name of Campaign",
from_name: "From Name",
reply_to: "[email protected]"
}
body = {
type: "regular",
recipients: recipients,
settings: settings
}
begin
gibbon.campaigns.create(body: body)
rescue Gibbon::MailChimpError => e
puts "Houston, we have a problem: #{e.message} - #{e.raw_body}"
endAdd content to a campaign:
(Please note that Mailchimp does not currently support dynamic replacement of mc:edit areas in their drag-and-drop templates using their API. Custom templates can be used instead.)
body = {
template: {
id: template_id,
sections: {
"name-of-mc-edit-area": "Content here"
}
}
}
gibbon.campaigns(campaign_id).content.upsert(body: body)Send a campaign:
gibbon.campaigns(campaign_id).actions.send.createSchedule a campaign:
body = {
schedule_time: "2016-06-27 20:00:00"
}gibbon.campaigns(campaign_id).actions.schedule.create(body: body)Interests are a little more complicated than other parts of the API, so here's an example of how you would set interests at subscription time or u
No open issues yet, or sync has not completed.