Integration walkthrough
A step-by-step guide to integrating EmailList into your application. This walkthrough covers everything from installation to sending emails with unsubscribe links.
What you'll learn
- How to install and configure the EmailList API client
- How to create projects and lists (manually or programmatically)
- How to import existing users using bulk operations (optional)
- How to sync your user model with EmailList contacts
- How to fetch contacts before sending emails
- How to include unsubscribe links in your email templates
Step 1: Installation
First, install and configure the EmailList API client. For detailed installation instructions, see the installation guide.
Quick start:
# Add to Gemfile
gem 'email_list_api'
# Configure in config/initializers/email_list_api.rb
EmailListApi.configure do |config|
config.api_key = ENV['EMAILLIST_API_KEY']
end
# Create client
client = EmailListApi::Client.new
Important: Store your API key in environment variables. Never commit API keys to version control. Get your API key from the dashboard → Settings → API keys.
Step 2: Create projects and lists
Projects are top-level containers for organizing your email lists. Lists are collections of contacts within a project. You can create them manually through the dashboard or programmatically via the API.
Option A: Create manually
Use the dashboard to create projects and lists:
- Sign in to your EmailList dashboard
- Navigate to Projects → Create new project
- Within your project, create lists as needed
Option B: Create programmatically
Create projects and lists programmatically when your app starts or deploys. Use the upsert endpoints to ensure they exist without errors if they're already created:
# Create or get existing project (fails gracefully if already exists)
def ensure_project_exists(client, project_name)
begin
response = client.upsert_project(name: project_name)
project_id = response[:data][:id]
Rails.logger.info "Project '#{project_name}' ready (ID: #{project_id})"
project_id
rescue => e
Rails.logger.error "Failed to create project: #{e.message}"
# Optionally, try to find existing project
projects = client.projects
existing = projects[:data].find { |p| p[:name] == project_name }
existing&.dig(:id) || raise
end
end
# Create or get existing list (fails gracefully if already exists)
def ensure_list_exists(client, project_id, list_name)
begin
response = client.upsert_list(
project_id: project_id,
name: list_name
)
list_id = response[:data][:id]
Rails.logger.info "List '#{list_name}' ready (ID: #{list_id})"
list_id
rescue => e
Rails.logger.error "Failed to create list: #{e.message}"
# Optionally, try to find existing list
lists = client.lists(project_id: project_id)
existing = lists[:data].find { |l| l[:name] == list_name }
existing&.dig(:id) || raise
end
end
# Use in an initializer or startup script
Rails.application.config.after_initialize do
client = EmailListApi::Client.new
project_id = ensure_project_exists(client, 'My App')
ensure_list_exists(client, project_id, 'Newsletter')
ensure_list_exists(client, project_id, 'Product Updates')
end
Tip: The upsert endpoints return 201 Created for new resources and 200 OK for existing ones, making them perfect for initialization scripts that run on every deploy.
Step 3: Import existing users (optional)
If you have existing users in your application, you can import them all at once using the bulk operations endpoint. This is a one-time operation to get your existing user base into EmailList.
Note
This step is optional and only needed if you have existing users to import. For new users going forward, use Step 4 to sync them automatically.
# Import all existing users using bulk operations
client = EmailListApi::Client.new
project_id = ENV['EMAILLIST_PROJECT_ID'].to_i
# Fetch all users from your database
users = User.all
# Prepare contacts array (process in batches for large datasets)
contacts = users.map do |user|
{
email: user.email,
first_name: user.first_name,
last_name: user.last_name
}
end
# Import in batches (API processes up to 10,000 at a time)
contacts.each_slice(1000) do |batch|
begin
response = client.bulk_create_contacts(
project_id: project_id,
contacts: batch
)
created = response[:data][:created]
failed = response[:data][:failed]
Rails.logger.info "Imported #{created} contacts, #{failed} failed"
# Log any errors
if response[:data][:errors].any?
Rails.logger.warn "Errors: #{response[:data][:errors].inspect}"
end
rescue => e
Rails.logger.error "Failed to import batch: #{e.message}"
# Continue with next batch even if one fails
end
end
Tips: The bulk endpoint processes contacts in batches of 10,000. Duplicate emails and existing contacts are automatically skipped. For large imports, process in smaller batches (1,000-5,000) to avoid timeouts. See the bulk operations documentation for more details.
Step 4: Integrate with your user model
Sync your application's users with EmailList contacts. When a user signs up or updates their information, create or update their contact in EmailList.
Using the upsert endpoint
The upsert endpoint creates a contact if it doesn't exist, or updates it if it does. This is perfect for syncing users:
# In your User model or service
class User < ApplicationRecord
after_create :sync_to_email_list
after_update :sync_to_email_list, if: :saved_change_to_email?
private
def sync_to_email_list
return unless email.present?
client = EmailListApi::Client.new
begin
# Upsert contact - creates if new, updates if exists
client.upsert_contact(
project_id: ENV['EMAILLIST_PROJECT_ID'].to_i,
email: email,
first_name: first_name,
last_name: last_name
)
# Optionally add to a list
if newsletter_subscribed?
client.add_contacts_to_list(
project_id: ENV['EMAILLIST_PROJECT_ID'].to_i,
list_id: ENV['EMAILLIST_NEWSLETTER_LIST_ID'].to_i,
contacts: [{ email: email }]
)
end
rescue => e
# Fail gracefully - log error but don't break user signup
Rails.logger.error "Failed to sync user to EmailList: #{e.message}"
# Optionally use an error tracking service like Sentry
# Sentry.capture_exception(e)
end
end
end
Rails integration (automatic syncing)
If you're using Ruby on Rails, the EmailList API gem includes a concern that automatically syncs your models:
class User < ApplicationRecord
include EmailListApi::SyncsEmailListContact
# Automatically syncs when user is created or updated
syncs_email_list_contact project_slug: 'my-app'
end
Learn more about the Rails integration →
Important: Fail gracefully
Always wrap EmailList API calls in error handling. If the API is temporarily unavailable, your user signup/update process should still succeed. Log errors for monitoring, but don't let EmailList failures break your core application flow.
Step 5: Get contacts before sending emails
Before sending emails, fetch the contacts from your list. The API response includes unsubscribe URLs that you'll need for each contact.
# Fetch all contacts from a list (with pagination)
def fetch_all_contacts(client, project_id, list_id)
contacts = []
page = 1
loop do
response = client.list_contacts(
project_id: project_id,
list_id: list_id,
page: page
)
page_contacts = response[:data]
break if page_contacts.empty?
contacts.concat(page_contacts)
# Check if there are more pages
meta = response[:meta]
break if page >= meta[:total_pages]
page += 1
end
contacts
end
# Use before sending emails
client = EmailListApi::Client.new
contacts = fetch_all_contacts(
client,
ENV['EMAILLIST_PROJECT_ID'].to_i,
ENV['EMAILLIST_NEWSLETTER_LIST_ID'].to_i
)
contacts.each do |contact|
email = contact[:email]
unsubscribe_url = contact[:unsubscribe_url]
# Send email with unsubscribe link
send_email(email, unsubscribe_url)
end
Note: Always fetch contacts right before sending emails to ensure you have the latest unsubscribe URLs. The API paginates results (25 per page by default), so make sure to handle pagination if you have more contacts.
Step 6: Include unsubscribe links in email templates
Each contact response includes an unsubscribe_url that you must include in your email templates. This URL is unique to each contact-list combination and allows recipients to unsubscribe without authentication.
Here's an example showing how to include the unsubscribe URL in your email templates:
Note: In your ERB email template, use <%= unsubscribe_url %> to output the unsubscribe URL. In JavaScript template strings, use ${unsubscribeUrl}.
# When sending emails to contacts from a list
contacts.each do |contact|
unsubscribe_url = contact[:unsubscribe_url]
# Render email template with unsubscribe URL
# In your ERB template, use: <a href="UNSUBSCRIBE_URL">Unsubscribe</a>
# Replace UNSUBSCRIBE_URL with the unsubscribe_url variable
email_body = render_email_template(
contact: contact,
unsubscribe_url: unsubscribe_url
)
# Send email using your email service (e.g., ActionMailer, SendGrid, etc.)
send_email(
to: contact[:email],
subject: 'Your weekly newsletter',
body: email_body
)
end
Best practices
- Always include unsubscribe links in every marketing email (required by CAN-SPAM, GDPR, etc.)
- Place the unsubscribe link in the footer where recipients can easily find it
- Use clear, user-friendly text like "Unsubscribe" or "Manage preferences"
- Fetch unsubscribe URLs right before sending to ensure they're current and valid
- Each unsubscribe URL is specific to a contact-list combination
For more details on unsubscribe URLs, see the unsubscribe URLs documentation.
Complete example
Here's a complete example that ties everything together:
# Complete integration example
class NewsletterService
def initialize
@client = EmailListApi::Client.new
@project_id = ENV['EMAILLIST_PROJECT_ID'].to_i
@list_id = ENV['EMAILLIST_NEWSLETTER_LIST_ID'].to_i
end
# Send newsletter to all subscribers
def send_newsletter
contacts = fetch_all_contacts
contacts.each do |contact|
next unless contact[:unsubscribe_url] # Skip if no unsubscribe URL
begin
send_email_with_unsubscribe(
to: contact[:email],
unsubscribe_url: contact[:unsubscribe_url]
)
rescue => e
Rails.logger.error "Failed to send email to #{contact[:email]}: #{e.message}"
# Continue with other contacts even if one fails
end
end
end
private
def fetch_all_contacts
contacts = []
page = 1
loop do
response = @client.list_contacts(
project_id: @project_id,
list_id: @list_id,
page: page
)
page_contacts = response[:data]
break if page_contacts.empty?
contacts.concat(page_contacts)
meta = response[:meta]
break if page >= meta[:total_pages]
page += 1
end
contacts
end
def send_email_with_unsubscribe(to:, unsubscribe_url:)
# Render your email template with the unsubscribe URL
email_body = render_email_template(unsubscribe_url: unsubscribe_url)
# Send using your email service (ActionMailer, SendGrid, etc.)
NewsletterMailer.weekly_update(
to: to,
body: email_body
).deliver_now
end
def render_email_template(unsubscribe_url:)
# Your email template rendering logic
# Include the unsubscribe_url in the template
end
end
Next steps
- Installation guide - Detailed installation instructions
- Projects API - Complete API reference for projects
- Lists API - Complete API reference for lists
- Contacts API - Complete API reference for contacts
- Unsubscribe URLs - Detailed guide on unsubscribe URLs
- Ruby SDK - Rails integration and automatic syncing