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 /audiences
  • GET|POST /audiences/{id}/contacts
  • DELETE /audiences/{id}/contacts/{email}
  • GET|POST /broadcasts
  • POST /broadcasts/{id}/test
  • POST /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.