Loops
Trigger a published Loops transactional email for one recipient, with metadata delivered as dataVariables.
Capabilities
| Repeated headers | Idempotency | Scheduling | Personalized |
|---|---|---|---|
| No | none | No | expanded |
These values come from the adapter's exported capabilities declaration. The field support matrix covers normalized message fields.
The Loops adapter calls the Loops transactional API with plain fetch. It triggers a published transactional email by transactionalId for exactly one recipient and hands your message to the template as dataVariables.
Configure
Create an API key in Loops with permission to send transactional email, then publish the transactional email and copy its transactionalId.
import { createEmailClient } from "@opencoredev/email-sdk";
import { loops } from "@opencoredev/email-sdk/loops";
export const email = createEmailClient({
adapters: [
loops({
apiKey: process.env.LOOPS_API_KEY!,
transactionalId: process.env.LOOPS_TRANSACTIONAL_ID!,
}),
],
});Prop
Type
Send
The Loops template renders the email. The adapter merges subject, html, text, from, and every metadata key into dataVariables; your template decides which of them appear. Exactly one to recipient is allowed per send.
const result = await email.send({
from: "Acme <hello@acme.com>",
to: "user@example.com",
subject: "Reset your password",
html: "<p>Use the button below to reset your password.</p>",
metadata: {
firstName: "Ada",
resetUrl: "https://acme.com/reset/abc123",
},
});
console.log(result.id); // Loops id (or transactionalId) from the responseAttachments are supported and sent as { filename, contentType, data } with base64-encoded content.
Attachments need account enablement
Loops only accepts transactional attachments on accounts where the capability has been enabled.
Without it, sends with attachments fail at the API. Also note cc, bcc, replyTo, headers,
and tags throw an EmailValidationError before any request; see field
support.
Verify from the CLI
LOOPS_API_KEY="..." LOOPS_TRANSACTIONAL_ID="cm..." npx --package @opencoredev/email-sdk email-sdk doctor --adapter loopsLOOPS_API_KEY="..." LOOPS_TRANSACTIONAL_ID="cm..." npx --package @opencoredev/email-sdk email-sdk send \
--adapter loops \
--from "Acme <hello@acme.com>" \
--to user@example.com \
--subject "Loops smoke test" \
--text "It works" \
--dry-runDrop --dry-run to trigger one real template send and confirm the API key and published transactional email are live.
Compare Loops with other providers
Side-by-side message-field support from the SDK capability matrix, with working code for both adapters:
Frequently asked questions
Does Email SDK support Loops?
Yes. Email SDK ships a Loops adapter imported from @opencoredev/email-sdk/loops. You keep your Loops account and credentials; the SDK adds message validation, typed errors, and no-network test adapters around the same send() call used for every other provider.
Which message fields does the Loops adapter support?
Loops supports Attachments and Metadata. It does not support CC recipients, BCC recipients, Reply-To address, Custom headers, Tags, and Scheduled sending (sendAt); Email SDK rejects a message that uses those fields before any request is made.
Can Loops schedule email for later with Email SDK?
No. Loops has no provider-side scheduling, so a message with sendAt fails validation. Store the job in your own queue and send when it is due.
Does the Loops adapter support idempotent sends?
No. Loops has no provider-side idempotency, so a retried send can be delivered twice. Deduplicate in your own queue before retrying.