Back to Blog

How to Send Emails in Hono (2026 Guide)

10 min read

Hono is a lightweight web framework that runs on Cloudflare Workers, Deno, Bun, and Node.js. It uses the Web Standards API (fetch, Request, Response), so email sending works the same across all runtimes.

This guide covers Hono routes, middleware patterns, and edge deployment.

Install

Terminal
npm install hono sequenzy
Terminal
npm install hono resend
Terminal
npm install hono @sendgrid/mail

Send from a Route

src/index.ts
import { Hono } from "hono";
import Sequenzy from "sequenzy";

const app = new Hono();
const sequenzy = new Sequenzy();

app.post("/api/send-welcome", async (c) => {
const { email, name } = await c.req.json();

if (!email || !name) {
  return c.json({ error: "email and name required" }, 400);
}

try {
  const result = await sequenzy.transactional.send({
    to: email,
    subject: `Welcome, ${name}`,
    body: `<h1>Welcome, ${name}</h1><p>Your account is ready.</p>`,
  });

  return c.json({ jobId: result.jobId });
} catch {
  return c.json({ error: "Failed to send" }, 500);
}
});

app.post("/api/contact", async (c) => {
const { email, message } = await c.req.json();

if (!email || !message) {
  return c.json({ error: "email and message required" }, 400);
}

await sequenzy.transactional.send({
  to: "you@yourcompany.com",
  subject: `Contact from ${email}`,
  body: `<p><strong>From:</strong> ${email}</p><p>${message}</p>`,
});

return c.json({ sent: true });
});

export default app;
src/index.ts
import { Hono } from "hono";
import { Resend } from "resend";

const app = new Hono();
const resend = new Resend(process.env.RESEND_API_KEY);
const FROM = "Your App <noreply@yourdomain.com>";

app.post("/api/send-welcome", async (c) => {
const { email, name } = await c.req.json();

if (!email || !name) {
  return c.json({ error: "email and name required" }, 400);
}

const { data, error } = await resend.emails.send({
  from: FROM,
  to: email,
  subject: `Welcome, ${name}`,
  html: `<h1>Welcome, ${name}</h1><p>Your account is ready.</p>`,
});

if (error) {
  return c.json({ error: error.message }, 500);
}

return c.json({ id: data?.id });
});

export default app;
src/index.ts
import { Hono } from "hono";
import sgMail from "@sendgrid/mail";

sgMail.setApiKey(process.env.SENDGRID_API_KEY!);

const app = new Hono();

app.post("/api/send-welcome", async (c) => {
const { email, name } = await c.req.json();

if (!email || !name) {
  return c.json({ error: "email and name required" }, 400);
}

try {
  await sgMail.send({
    to: email,
    from: "noreply@yourdomain.com",
    subject: `Welcome, ${name}`,
    html: `<h1>Welcome, ${name}</h1><p>Your account is ready.</p>`,
  });

  return c.json({ sent: true });
} catch {
  return c.json({ error: "Failed to send" }, 500);
}
});

export default app;

Cloudflare Workers

On Cloudflare Workers, use environment bindings instead of process.env:

// src/index.ts
import { Hono } from "hono";
 
type Bindings = {
  SEQUENZY_API_KEY: string;
};
 
const app = new Hono<{ Bindings: Bindings }>();
 
app.post("/api/send-welcome", async (c) => {
  const { email, name } = await c.req.json();
 
  const response = await fetch("https://api.sequenzy.com/v1/transactional/send", {
    method: "POST",
    headers: {
      "Authorization": `Bearer ${c.env.SEQUENZY_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      to: email,
      subject: `Welcome, ${name}`,
      body: `<h1>Welcome, ${name}</h1><p>Your account is ready.</p>`,
    }),
  });
 
  return c.json(await response.json());
});
 
export default app;

Grouped Routes

import { Hono } from "hono";
import Sequenzy from "sequenzy";
 
const email = new Hono();
const sequenzy = new Sequenzy();
 
email.post("/welcome", async (c) => {
  const { email, name } = await c.req.json();
  const result = await sequenzy.transactional.send({
    to: email,
    subject: `Welcome, ${name}`,
    body: `<h1>Welcome, ${name}</h1>`,
  });
  return c.json(result);
});
 
email.post("/contact", async (c) => {
  const { email, message } = await c.req.json();
  await sequenzy.transactional.send({
    to: "you@yourcompany.com",
    subject: `Contact from ${email}`,
    body: `<p>${message}</p>`,
  });
  return c.json({ sent: true });
});
 
// Mount in main app
const app = new Hono();
app.route("/api/email", email);

Going to Production

1. Verify Your Domain

Add SPF, DKIM, DMARC DNS records.

2. Choose Your Runtime

Hono runs everywhere. Deploy to Cloudflare Workers, Deno Deploy, or any Node.js host.

3. Use Secrets

On Cloudflare Workers: wrangler secret put SEQUENZY_API_KEY

Beyond Transactional

Sequenzy handles transactional sends, marketing campaigns, automated sequences, and subscriber management from one API. Native Stripe integration for SaaS.

Wrapping Up

  1. Hono routes with typed context
  2. Cloudflare Workers with environment bindings
  3. Grouped routes for organized email endpoints
  4. Multi-runtime support across all platforms

Pick your provider, copy the patterns, and start sending.