Selligent
Send transactional emails via the Selligent (Marigold Engage) SDC API
The Selligent transport is an official Better-Notify package that sends transactional email through the Selligent Delivery Cloud (SDC) HTTP API. It uses plain fetch() with zero external dependencies, so it works in Node.js, Bun, Cloudflare Workers, and any runtime with a global fetch.
Unlike API-key-based transports, Selligent uses OAuth 2.0 client credentials. The transport handles token management automatically — fetching, caching, and refreshing tokens as needed.
Getting your credentials
- Log in to Selligent / Marigold Engage.
- Navigate to Admin Config → Access Management → Service Accounts.
- Add a new Service Account — enter an account name, select type Custom, and click Save.
- Copy the generated client ID, client secret, and account ID.
- Under the service account's endpoint access, enable the SDC transactional email (
/email/v1/messages/send) and OAuth token (/oauth/token) endpoints.
Store them as environment variables:
SELLIGENT_CLIENT_ID=12345
SELLIGENT_CLIENT_SECRET=your_client_secret
SELLIGENT_ACCOUNT_ID=your_account_idInstall
npm install @betternotify/selligent @betternotify/core @betternotify/emailUsage
import { createNotify, createClient } from '@betternotify/core';
import { emailChannel } from '@betternotify/email';
import { selligentTransport } from '@betternotify/selligent';
const email = emailChannel({
defaults: { from: { name: 'My App', email: 'noreply@example.com' } },
});
const rpc = createNotify({ channels: { email } });
const catalog = rpc.catalog({
/* routes */
});
const mail = createClient({
catalog,
transportsByChannel: {
email: selligentTransport({
clientId: Number(process.env.SELLIGENT_CLIENT_ID!),
clientSecret: process.env.SELLIGENT_CLIENT_SECRET!,
accountId: process.env.SELLIGENT_ACCOUNT_ID!,
}),
},
});Custom token provider
If you already manage OAuth tokens externally, pass getAccessToken instead of credentials:
selligentTransport({
getAccessToken: () => myTokenManager.getToken(),
});Verifying credentials
Use verify() to test credentials without sending an email. It attempts to fetch an OAuth token and returns { ok: true } on success:
const transport = selligentTransport({ /* ... */ });
const result = await transport.verify();
if (!result.ok) {
console.error('Credential check failed:', result.details);
}Options
Prop
Type
Per-send overrides
Pass Selligent-specific fields per-send via the transport key in .send():
await mail.welcome.send({
to: 'user@example.com',
input: { name: 'Jane' },
transport: {
selligent: {
profile: 'crm-id-123',
tags: ['campaign-spring'],
metadata: '{"ref": 123}',
list_unsubscribe: '<https://example.com/unsub>',
custom_send_time: '2025-09-02T12:00:00',
time_to_live: 'P2D',
},
},
});Prop
Type
Multiple recipients
When you send to multiple to addresses, the transport creates one SDC message item per recipient in a single HTTP request (SDC accepts a JSON array). Each item gets its own reference (messageId-0, messageId-1, etc.) and context.profile (defaults to the recipient email).
Authentication flow
The transport uses the OAuth 2.0 client credentials grant:
- Before the first send, it
POSTs to the token endpoint with yourclientId,clientSecret,accountId, andaudience. - The returned JWT is cached in-process and reused for subsequent sends.
- When the token is within 60 seconds of expiry, the next send triggers a fresh token fetch.
Token endpoint failures during send return a CONFIG error (non-retriable for 4xx, retriable for 5xx).
SDC sends message content without any modifications — it does not inject tracking pixels or rewrite links. Open/click tracking must be implemented by the sender.
Error handling
The transport maps HTTP status codes to Better-Notify error codes using the shared mapHttpStatus utility:
| HTTP status | Better-Notify code | Retriable |
|---|---|---|
| 400 | VALIDATION | No |
| 422 | VALIDATION | No |
| 401 | CONFIG | No |
| 403 | CONFIG | No |
| 429 | RATE_LIMITED | Yes |
| 5xx | PROVIDER | Yes |
Network failures are wrapped as PROVIDER errors and timeouts as TIMEOUT errors.
OAuth token failures are surfaced as CONFIG errors with the HTTP status from the token endpoint.
Dropped fields
The following RenderedMessage fields are not part of SDC's send schema and are silently dropped: cc, bcc, custom headers, tags, priority, and inlineAssets. If you need them, prefer a dedicated email provider transport (e.g. Resend, SMTP).