Newsletter
Manage marketing email subscription status with Resend Contacts and a Dashboard settings switch.
ShipNext newsletter support manages marketing subscription state. It is separate from transactional email:
- Transactional email: verification, reset password, magic links, in
src/modules/email/. - Newsletter: marketing subscribe/unsubscribe, in
src/modules/newsletter/.
The current implementation uses Resend Contacts and does not store newsletter rows in the local database.
Configuration
config/website.ts:
const newsletterConfig = {
provider: "resend",
};src/modules/newsletter/index.ts chooses the provider from websiteConfig.newsletter.provider. Currently only resend is supported.
Environment variables
Newsletter and transactional email share the Resend API key:
RESEND_API_KEY=''If it is missing, the first subscription query or update throws RESEND_API_KEY environment variable is not set.
HTTP API
Route:
src/app/api/newsletter/route.tsGET /api/newsletter
Returns the current logged-in user's subscription status:
{
"email": "[email protected]",
"subscribed": true
}PATCH /api/newsletter
Updates the current logged-in user's status:
{
"subscribed": false
}The provider first looks up the Contact. If it exists, it updates unsubscribed; otherwise it creates a Contact.
Dashboard usage
The settings UI uses NewsletterSettings:
src/shared/components/dashboard/settings/newsletter-settings.tsxWhen the user toggles the switch, the component calls PATCH /api/newsletter. On success it shows feedback; on failure it rolls back the UI state.
Current boundaries
- This only tracks subscribe/unsubscribe status.
- It does not include a campaign editor, analytics, or multiple lists.
GETandPATCHrequire a logged-in user.- If a user changes email address, decide whether to sync or archive the old Contact.
Checklist
-
.env.localhasRESEND_API_KEY. - Logged-in users can see their current email in Dashboard newsletter settings.
- Toggling the switch updates Resend Contacts.
- Unauthenticated requests return an auth error instead of a generic 500.
Related docs: