Skip to content

Inbound email

Receive email at an address on your own domain or at a hosted mailfully.app address. Each message reaches your server as an email.received webhook, and the API returns its body and attachments. Received mail shares the monthly allowance with the mail you send.

Two ways to get an address

  • A hosted address such as support@k7q2m9xa.mailfully.app. The label before .mailfully.app is eight random letters and digits. It needs no DNS: an owner or admin turns it on in the dashboard settings.
  • An address on your own verified domain. Turn receiving on for the domain and publish one MX record.

If your domain's MX records already point at another mail provider like Google Workspace or Microsoft 365, Mailfully refuses to turn receiving on there. Use a subdomain such as inbound.yourdomain.com instead, and your existing mailboxes are untouched.

Both kinds of address are catch-all, so any name before the @ sign is accepted.

What gets accepted

  • Each message can be up to 40 MB, attachments included.
  • Spam is kept and marked with spam: "FAIL", so you can filter it yourself.
  • A message with a virus keeps only its metadata.

Get each message by webhook

When mail arrives, your endpoint gets an email.received webhook with the message metadata. Webhooks are signed, so you can check that a request came from us.

Call GET /v1/emails/receiving/{id} with a key that has the read:inbound scope. It returns the body and the attachment list. The files come from GET /v1/emails/receiving/{id}/attachments, which gives each attachment a download link.

webhook.tsts
import { Mailfully } from "mailfully";

const mailfully = new Mailfully({
  apiKey: process.env.MAILFULLY_API_KEY ?? "",
});

export async function POST(request: Request) {
  const rawBody = await request.text();
  // Verify the webhook-signature header first; see the webhooks guide.
  const event = JSON.parse(rawBody);

  if (event.type === "email.received") {
    const { data, error } = await mailfully.emails.receiving.get(
      event.data.email_id,
    );
    if (error) throw new Error(`${error.type}: ${error.message}`);
    console.log(data.text);
  }

  return new Response("ok");
}

What it costs

  • Each received email counts once toward your monthly allowance.
  • Spam and virus failures are not counted.
  • It does not count toward daily sending limits.
  • On a paid plan, received mail past your allowance is billed like sent mail, at $0.40 per 1,000 emails.
  • Mail that arrives after you reach your plan's limit (the allowance on Free, five times the allowance on a paid plan) is stored but locked until your usage is back under it. Locked mail is never billed.

On the Free plan, a flood of incoming mail can use up the allowance your sends need.

How long we keep it

Received mail follows your plan's retention window and is deleted when it ends.

  • Free: 30 days
  • Starter: 30 days
  • Growth: 60 days
  • Scale: 90 days