Documentation
Zero to send in under 10 minutes.
Mailfully is a transactional email API and SMTP relay on Amazon SES. This walkthrough takes you from an empty project to a real, inspectable send — with a no-domain test path so you can try it instantly.
The walkthrough
Create an account and get an API key
Sign up (3,000 emails/month free, no credit card), then mint an API key in the dashboard. Mint a test-environment key for step 4 and a live key for step 5. The plaintext key is shown exactly once — copy it somewhere safe.
Install the SDK
terminalbash npm i @mailfully/nodeSet MAILFULLY_API_KEY
The SDK never reads the environment itself — pass the key explicitly. Load it from an env var so it never lands in source control.
.envbash # .env — keep your key out of source control MAILFULLY_API_KEY=mf_live_…Send a TEST email — no domain required
With a test-environment key, every recipient is routed to the SES Mailbox Simulator, so you can send before verifying a domain. The recipient’s local-part picks the outcome —
bounce,complaint,success, and more. See test mode for every outcome.test-send.tsts // Test-mode fixture — exercise a simulated bounce with NO verified domain and // NO real mail. A REAL `@mailfully/node` script, typechecked by the gate's // `tsc` and rendered verbatim in the docs (read as text, never imported). // // When you send with a TEST-mode API key, every recipient is rewritten to the // SES Mailbox Simulator. The recipient's LOCAL-PART selects the simulated // outcome — one of `success`, `bounce`, `complaint`, `suppressionlist`, `ooto` // (anything else behaves like `success`). So `[email protected]` // (or any `bounce@…`) produces a simulated bounce you can watch flow through // the message's events and your webhooks. import { Mailfully } from "@mailfully/node"; // Use a TEST-environment key here (mint one in the dashboard or via the API). const mailfully = new Mailfully({ apiKey: process.env.MAILFULLY_TEST_API_KEY ?? "", }); const { data, error } = await mailfully.emails.send({ from: "[email protected]", // The local-part `bounce` drives the simulated outcome. You can target the // simulator domain directly, or any address — test mode rewrites it for you. to: "[email protected]", subject: "Simulated bounce", text: "This message never reaches a real inbox.", }); if (error) { console.error(`Test send failed (${error.statusCode}):`, error.message); } else { // Inspect the simulated bounce on the message's event timeline. const events = await mailfully.emails.events(data.id); if (events.error) { console.error("Could not load events:", events.error.message); } else { for (const event of events.data.data) { console.log(`${event.event_at} ${event.type}`); } } }Send a real email from a verified domain
Add a domain in the dashboard (or with
mailfully.domains.create), publish the DKIM/SPF records it returns, and verify it. Then swap in your live key and send for real:send.tsts // Quickstart fixture — Next.js Route Handler / Server Action. // // This is a REAL, copy-pasteable `@mailfully/node` script. It is typechecked // against the published SDK types by the marketing app's `tsc` gate (it lives // under `src`). The docs pages render this file's SOURCE TEXT verbatim — they // never IMPORT it — so the SDK is shown exactly as a developer would write it // while staying entirely out of the Next bundle. import { Mailfully } from "@mailfully/node"; const mailfully = new Mailfully({ apiKey: process.env.MAILFULLY_API_KEY ?? "", // never hard-code your key }); const { data, error } = await mailfully.emails.send({ from: "[email protected]", to: "[email protected]", subject: "Welcome aboard", html: "<p>Thanks for signing up!</p>", }); if (error) { // No method ever throws — failures arrive on the error arm. console.error(`Send failed (${error.statusCode}):`, error.message); } else { console.log("Queued email id:", data.id); }Inspect the message, its events, and the debug log
Use the returned id to read the message detail (
mailfully.emails.get(id)) and its full event timeline (mailfully.emails.events(id)) — accepted, the raw SES message id, deliveries, opens, bounces, and complaints. The dashboard shows the same timeline plus the per-message debug log, including the SMTP conversation and the provider response, so when a send misbehaves you can see exactly what happened.
Keep going
Ready to send?
Grab a key and run the test send above — it works before you verify a single DNS record.
Start free