Skip to content

Send from a client · Published 2026-09-22 · Updated 2026-09-29 · AgentiSend

Send email from a Lovable app

To send email from a Lovable app, verify a domain, create a key with a budget, store it as a project secret, and ask Lovable to add a server-side send.

To send email from a Lovable app, verify a domain, create a key with sending_access and a budget, store it as a project secret, and ask Lovable to add a server-side send that calls the API. Lovable has no AgentiSend connector. This page does not describe one, and turning on a third-party email connector is not the path.

Why the sample is Hono

Lovable's edge functions run on Deno. The SDK the sample uses is plain fetch with no Node built-ins, so the Hono file below runs on Deno unchanged. It is also run by the test suite against a local AgentiSend server, so the code you ask Lovable for is code that has already run.

Before you prompt

  1. Verify the sending domain. The From address has to be on it.
  2. Create the key with POST /api-keys and permission sending_access, then give it a ceiling with PATCH /limits/keys/{id}.
  3. Add two project secrets: AGENTISEND_API_KEY for the key and MAIL_FROM for the sender. Both are environment variables the edge function reads on the server. Neither belongs in a component, where the browser would receive it.

The prompt to paste

Add an edge function that sends one transactional email through AgentiSend. There is no native AgentiSend connector, and a different email connector is not a substitute. Follow the Hono sample at https://agentisend.com/docs/guides/hono and the contract at https://agentisend.com/openapi.json, using the npm package agentisend. Read the key from the project secret AGENTISEND_API_KEY and the sender from MAIL_FROM, on the server only. Pass an idempotency key built from the recipient so a retry does not mail twice. When the API refuses, return its code and fix to the caller, and do not retry when retryable is false.

The code that prompt should produce

/**
 * Hono — one POST route that sends a transactional email.
 *
 * Hono runs on Workers, Deno, Bun and Node, and the AgentiSend SDK is plain
 * fetch with no Node built-ins, so this file is the same on all of them.
 */
import { Hono } from 'hono';
import { AgentiSend, AgentiSendError } from 'agentisend';

const agentisend = new AgentiSend();

function mailFrom(): string {
  const from = process.env.MAIL_FROM;
  if (!from) throw new Error('Set MAIL_FROM to an address on a domain you have verified.');
  return from;
}

export const app = new Hono();

app.post('/send', async (c) => {
  const { email, subject, body } = await c.req.json<{
    email?: string;
    subject?: string;
    body?: string;
  }>();
  if (!email) return c.json({ error: 'email is required' }, 400);

  try {
    const { id } = await agentisend.emails.send(
      {
        from: mailFrom(),
        to: email,
        subject: subject ?? 'Your receipt',
        text: body ?? 'Thanks — your receipt is attached to your account.',
      },
      { idempotencyKey: `receipt/${email}` },
    );
    return c.json({ id });
  } catch (err) {
    if (err instanceof AgentiSendError) {
      // `fix` names the endpoint that repairs the call, so a client can act on
      // the failure without a human reading prose.
      return c.json({ code: err.code, fix: err.fix }, 502);
    }
    throw err;
  }
});

export default app;
examples/hono/app.ts, run by the test suite against a local AgentiSend server

One POST route. It reads email, subject and body from the request, sends, and returns the message id. The idempotency key is receipt/ plus the address, so a retried call replays the first send instead of mailing twice. A refusal comes back as code and fix, which the app can show as they are.

Test it before the domain is ready

Point the first call at success@simulator.agentisend.com. Simulator addresses cost nothing, reach nobody, and work before your domain is verified, so the function can be proven while DNS is still settling. GET /emails/{id} with the returned id shows the message moving from queued to delivered.

The same limits from every client

Budgets, loop detection, approvals and the kill switch behave identically whichever client holds the key, so they are not repeated here. The guardrails checklist maps each item people are told to hand-write onto the request that already enforces it, and Email for AI agents names every control with its endpoint.

Next