Loops
Configure the Loops transactional email adapter.
@opencoredev/email-sdk/loopsLoops sends through a published Loops transactional email. It is best for product-triggered lifecycle messages where the template lives in Loops and your app passes data variables.
Before live sends
Create or publish the transactional email in Loops, copy its transactionalId, and create an API key with permission to send transactional email. Loops may require account-level enablement for attachments, so omit attachments until that capability is enabled.
Configure
import { createEmailClient } from "@opencoredev/email-sdk";
import { loops } from "@opencoredev/email-sdk/loops";
const email = createEmailClient({
adapters: [
loops({
apiKey: process.env.LOOPS_API_KEY!,
transactionalId: process.env.LOOPS_TRANSACTIONAL_ID!,
}),
],
});Send
const result = await email.send({
from: "Acme <hello@acme.com>",
to: "user@example.com",
subject: "Welcome",
html: "<p>Your workspace is ready.</p>",
metadata: {
firstName: "Ada",
workspaceName: "Acme",
},
});
console.log(result.provider, result.id);Loops maps metadata into dataVariables together with subject, html, text, and from. It only supports one recipient per transactional send.
Send with an attachment
await email.send({
from: "Acme <hello@acme.com>",
to: "user@example.com",
subject: "Export ready",
text: "Your export is attached.",
metadata: {
firstName: "Ada",
},
attachments: [
{
filename: "export.txt",
content: "name,total\nAda,42",
contentType: "text/plain",
},
],
});Options
| Option | Type | Required | Notes |
|---|---|---|---|
apiKey | string | Yes | Loops API key. |
transactionalId | string | Yes | Transactional email ID. |
baseUrl | string | No | Defaults to https://app.loops.so. |
fetch | typeof fetch | No | Useful for tests or custom runtimes. |
Loops transactional sends support one recipient, metadata through dataVariables, and attachments through the transactional attachments payload. Loops documents that attachments require support enablement on the account, so accounts without that enablement should omit attachments. Unsupported fields throw before the API call.
Response
The adapter maps Loops id or transactionalId to the normalized id field when the API returns one.
CLI smoke test
LOOPS_API_KEY="loops_..." \
LOOPS_TRANSACTIONAL_ID="cm..." \
npx email-sdk send \
--adapter loops \
--from "Acme <hello@acme.com>" \
--to user@example.com \
--subject "Loops test" \
--text "It works"