Skip to content

Send your first campaign

This guide takes you from subscribing to a sent campaign. The hands-on work takes about 30 minutes. Waiting on AWS for SES production access can add up to a day.

  • An AWS account where you can create CloudFormation stacks and IAM roles
  • DNS access for the domain you send from, for example example.com
  • Your physical mailing address, which is legally required in marketing email

Subscribe to Rhino Relay on AWS Marketplace, or use the link in your welcome email if you signed a contract with us directly. On the registration page, enter your company, your email, your AWS region (any region where SES sends email) and your sending domain. We email you an invitation to the console.

Sign in to the console. On the Setup page, click Launch in your AWS account. If you subscribed through AWS Marketplace, this opens Marketplace’s guided install. Otherwise it opens CloudFormation directly. Either way, everything is filled in.

The template creates data resources only: two DynamoDB tables, three S3 buckets, EventBridge rules that forward SES events and upload notices to us, a Firehose stream and a Glue table for your event archive, a CloudTrail trail (optional) and one IAM role our service uses. It contains no code. See exactly what it creates and every permission it grants.

Tick the IAM acknowledgement and click Create stack. It takes about 3 minutes. Back in the console, click Verify. The first check turns green when we’ve connected.

New AWS accounts can only send to verified addresses. In the SES console, open Account dashboard → Request production access, and paste the request text the Setup page gives you. It asks for your plan’s daily quota: 25,000 emails for Starter, 150,000 for Growth or 500,000 for Scale. AWS usually replies within a day.

The Setup page lists every record: three DKIM CNAMEs, the bounce. MX and SPF records, a DMARC record if you don’t have one, a track. CNAME, and two certificate validation records. Add them at your DNS provider. Each check turns green as it passes, usually within an hour.

5. Create an API key and save your settings

Section titled “5. Create an API key and save your settings”

On the API keys page, create a key with the admin scope and copy it. It’s shown only once.

Terminal window
export KEY="ek_..."
export BASE="https://api.rhinorelay.com/v1"
curl -X PATCH "$BASE/settings" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"defaultFromName":"Example Co","defaultFromEmail":"news@example.com","footerAddress":"Example Co, 1 Main St, Springfield, IL 62701, USA"}'
curl "$BASE/health" -H "Authorization: Bearer $KEY"

Every check should show "ok": true before you continue.

From Mailchimp, with an API key (Mailchimp → Profile → Extras → API keys):

Terminal window
curl -X POST "$BASE/imports/mailchimp" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"method":"apiKey","apiKey":"<mailchimp-key>","filters":{"engagedWithinDays":365}}'

Poll GET $BASE/imports/<id> until the state is dry_run_ready, then read the summary: how many contacts will be imported, how many stay suppressed, and how many were removed by cleaning. If it looks right:

Terminal window
curl -X POST "$BASE/imports/<id>/commit" -H "Authorization: Bearer $KEY" -H 'Idempotency-Key: import-1'

The Mailchimp key is stored in your account during the import and deleted when you commit. For a CSV file, use POST /imports/csv and upload to the uploadUrl it returns. That URL points to a bucket in your own account.

7. Create a template and send yourself a test

Section titled “7. Create a template and send yourself a test”
Terminal window
curl -X POST "$BASE/templates" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{
"name": "October newsletter",
"version": {
"subject": "Hi {{ contact.fields.FNAME | default: \"there\" }}, here is October",
"html": "<p>Hello!</p><p><a href=\"{{ unsubscribe_url }}\">Unsubscribe</a><br>{{ footer_address }}</p>",
"fromName": "Example Co", "fromEmail": "news@example.com"
}
}'
curl -X POST "$BASE/campaigns" -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
-d '{"name":"October","templateId":"<tp_...>","templateVersion":1,"segment":{},"stagePlan":{"type":"preset","name":"warmup"}}'
curl -X POST "$BASE/campaigns/<cm_...>/test" -H "Authorization: Bearer $KEY" -H 'Idempotency-Key: test-1' \
-H 'Content-Type: application/json' -d '{"to":["you@example.com"]}'

Check the test email arrives, and that its unsubscribe link works.

Terminal window
curl -X POST "$BASE/campaigns/<cm_...>/schedule" -H "Authorization: Bearer $KEY" -H 'Idempotency-Key: schedule-1'
curl "$BASE/campaigns/<cm_...>/report?by=stage" -H "Authorization: Bearer $KEY"

The warmup plan sends to your most engaged 2% first, then 8%, 20%, 30% and 40% a day apart, checking bounces and complaints before each stage. If either gets too high, the campaign pauses itself and emails you.

  • Use stagePlan: { type: "preset", name: "standard" } after your first campaign.
  • Subscribe to campaign.completed and contact.unsubscribed on your own EventBridge bus.
  • Read the security page to see what our service can access in your account, and how to check it in your CloudTrail.