Newsletters with SendNeo
Newsletters with SendNeo
SendNeo uses audiences for lists of contacts and broadcasts for one-time or scheduled newsletters. Audiences can have tags, a hosted sign-up page, an embeddable form, and a welcome email. You can write broadcasts in Markdown or HTML, preview them, send a test, schedule them, and publish a public archive.
Create an audience and add contacts
Create an audience with POST /audiences:
curl https://sendneo.yorkermedia.com/api/audiences \
-X POST \
-H "Authorization: Bearer $SENDNEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Product updates","slug":"product-updates"}'
Add a contact to an audience:
curl https://sendneo.yorkermedia.com/api/audiences/AUDIENCE_ID/contacts \
-X POST \
-H "Authorization: Bearer $SENDNEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"email":"reader@example.net","first_name":"Reader","tags":["beta"]}'
You can list contacts with GET /audiences/{id}/contacts and remove one with DELETE /audiences/{id}/contacts/{email}. Keep consent records in your own system when you need a detailed audit trail.
Hosted page and embed form
Every audience has a hosted sign-up page. You can also post a small form to the audience endpoint:
<form action="https://sendneo.yorkermedia.com/f/AUDIENCE_ID" method="post">
<label>
Email
<input type="email" name="email" required>
</label>
<label>
First name (optional)
<input type="text" name="first_name">
</label>
<button type="submit">Subscribe</button>
</form>
Replace AUDIENCE_ID with the real ID. Keep the form on an HTTPS page and explain what the subscriber will receive.
Double opt-in and welcome email
Double opt-in is on by default. A person confirms the address before becoming an active subscriber, which helps prevent typos and unwanted signups. Configure the welcome email for the audience so the first message sets expectations and provides a way to unsubscribe.
Do not silently add a person from a purchased, rented, scraped, or unrelated list. The acceptable-use policy describes the permission standard.
Write and send a broadcast
Create a broadcast with POST /broadcasts. Supply the audience, sender, subject, and Markdown or HTML content. Send a test with POST /broadcasts/{id}/test, then schedule or send it:
curl https://sendneo.yorkermedia.com/api/broadcasts/BROADCAST_ID/send \
-X POST \
-H "Authorization: Bearer $SENDNEO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"scheduled_at":"2026-10-16T18:00:00Z"}'
Omit scheduled_at to send now. Review the rendered preview, links, sender, audience, and test message before sending. A broadcast automatically includes one-click unsubscribe headers.
Archive
Each newsletter can have a public archive at https://sendneo.yorkermedia.com/n/<slug>. Choose a stable, readable slug and decide whether an issue belongs in the public archive before publishing it. Do not place private customer information in an archived issue.
Import a CSV
SendNeo imports CSV files from Kit, beehiiv, Substack, Mailchimp, and MailCheap. Include an email column and optionally a name column. The importer drops invalid, role, disposable, and duplicate addresses and keeps earlier unsubscribes suppressed. Review the import result before your first broadcast.
A clean import is not proof of consent. Keep the source and permission basis for each audience, and do not re-add people who previously unsubscribed.
Unsubscribe and postal address
Every marketing message needs a clear unsubscribe path. SendNeo handles one-click unsubscribe for broadcasts, and you should also make the link visible in the message body. Include your organization's current postal address in the footer to meet CAN-SPAM requirements. Keep the sender identity and subject line accurate.
Tracking is off by default. If you turn tracking on for a broadcast, remember that Apple Mail Privacy Protection makes open numbers unreliable. Delivered, bounced, complained, unsubscribed, and reply counts are more useful signals; see Deliverability.
API summary
GET|POST /audiencesGET|POST /audiences/{id}/contactsDELETE /audiences/{id}/contacts/{email}GET|POST /broadcastsPOST /broadcasts/{id}/testPOST /broadcasts/{id}/send
Use webhooks for contact.subscribed and contact.unsubscribed events, and keep transactional mail on the /emails lane so a newsletter workflow does not block a receipt or confirmation.
RSS-to-email
Each newsletter can follow your blog's RSS feed (newsletter → Settings → RSS-to-email). New posts become an issue: either a draft we email you about, or sent automatically to all subscribers. Posts already in the feed when you turn it on are never sent.
Open and click tracking (opt-in)
Tracking is off by default. Tick Track opens and clicks on a broadcast to count first opens and clicks per subscriber;
links are routed through SendNeo and a 1-pixel image is added. Security scanners and anything that "opens" mail within
seconds of delivery are ignored, and Apple Mail Privacy Protection still makes open rates rough — clicks are the better
signal. Webhook events email.opened and email.clicked fire for tracked broadcasts.
Custom fields and merge tags
Contacts can carry custom fields: "fields": {"company": "Acme", "plan": "pro"} on POST /audiences/{id}/contacts
(merged on PATCH; a null value removes a field). CSV imports keep extra columns as fields (e.g. a Plan Name column
becomes plan_name).
Use them anywhere in a broadcast, welcome email or sequence — subject included:
| Tag | Inserts |
|---|---|
{{first_name}}, {{last_name}}, {{email}} |
the contact's details |
{{company}} (any field name) |
that custom field |
{{company|your team}} |
the field, or the fallback when it is empty |
Values are HTML-escaped in the HTML part, so subscriber data can never change your email's markup.
A/B test the subject
Give a broadcast a Subject B (dashboard, or subject_b in the API). SendNeo sends each subject to half of a test group
(10–50% of the list), waits (1–24 hours), then sends the subject with more opens — or clicks — to everyone else. Tracking
switches on automatically for A/B tests. Lists under 20 people simply get subject A. Results appear on the broadcast page
and as ab_test in GET /broadcasts/{id}.
Duplicate a broadcast
Duplicate on any broadcast (or POST /broadcasts/{id}/duplicate) creates a new draft with the same content and settings.