Skip to content

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

  1. 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.

  2. Install the SDK

    terminalbash
    npm i @mailfully/node
  3. Set 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_…
  4. 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}`);
        }
      }
    }
  5. 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);
    }
  6. 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