Skip to content

hono-email/smtp provides a connector-based SMTP sender. You choose a runtime connector, instantiate SmtpTransport, and pass it to sendEmail().

import CloudflareConnector from 'hono-email/smtp/cloudflare'
import { Body, Html, Text, sendEmail } from 'hono-email'
import { SmtpTransport } from 'hono-email/smtp'
const dkimPrivateKey = `-----BEGIN PRIVATE KEY-----
...
-----END PRIVATE KEY-----`
const smtp = new SmtpTransport({
connector: CloudflareConnector,
hostname: 'smtp.example.com',
port: 587,
secure: 'starttls',
connectionTimeout: 10_000,
greetingTimeout: 10_000,
socketTimeout: 30_000,
auth: {
username: 'smtp-user',
password: 'smtp-password',
},
dkim: {
domainName: 'example.com',
keySelector: 'mail',
privateKey: dkimPrivateKey,
},
pool: {
maxConnections: 2,
maxMessages: 100,
},
limits: {
maxAttachmentSize: 10 * 1024 * 1024,
},
})
try {
await smtp.verify()
const receipt = await sendEmail({
adapter: smtp,
from: 'sender@example.com',
to: ['recipient@example.com', 'second@example.com'],
subject: 'Welcome',
envelope: {
from: 'bounces@example.com',
},
jsx: (
<Html>
<Body>
<Text>Hello from hono-email.</Text>
</Body>
</Html>
),
attachments: [
{
filename: 'invoice.txt',
content: 'Invoice text',
contentType: 'text/plain',
},
{
filename: 'logo.png',
href: 'https://example.com/assets/logo.png',
cid: 'logo',
contentDisposition: 'inline',
},
],
})
if (!receipt.successful) {
console.error(receipt.errorMessages)
}
} finally {
await smtp.close()
}

For the full list of configuration options, see the SMTP Options API Reference.

Entry point Runtime
hono-email/smtp/cloudflare Cloudflare Workers
hono-email/smtp/node Node.js
hono-email/smtp/deno Deno
hono-email/smtp/bun Bun
  • SMTP transport uses Web Streams internally. Runtime-specific socket support is supplied by the connector.
  • Cloudflare Workers does not allow outbound SMTP connections on port 25. Use submission ports such as 465 or 587.
  • Bun’s TCP API supports direct TLS connections, but the Bun connector does not support STARTTLS upgrade. Use port 465 with secure: true on Bun.

SmtpTransport reuses SMTP sessions until smtp.close() is called. The default pool size is 1, so sends on the same transport share one TCP connection sequentially.

  • Set pool.maxConnections to allow multiple concurrent SMTP sessions.
  • Set pool.maxMessages to retire a session after a fixed number of messages.
  • If a session fails during send, that session is discarded. The message is not retried automatically.
  • await smtp.verify() checks connection setup, TLS negotiation, and authentication without sending a message.
  • dkim can be configured on SmtpTransport or overridden per message to add a DKIM-Signature header before SMTP delivery.
  • envelope lets you override the SMTP envelope sender and recipients without changing the visible From / To headers.
  • to, cc, bcc, and envelope.to accept single addresses or arrays. SMTP sends one RCPT TO command per resolved recipient and reports partial recipient rejection in receipt.rejected.

Type: SmtpConnector

Runtime-specific TCP socket connector. Import one for your runtime:

Entry point Runtime
hono-email/smtp/node Node.js
hono-email/smtp/bun Bun
hono-email/smtp/deno Deno
hono-email/smtp/cloudflare Cloudflare Workers

Type: string

SMTP server hostname.

Type: number

SMTP server port. Use 587 for STARTTLS submission, 465 for implicit TLS.

Type: boolean | 'starttls' · Default: 'starttls'

TLS mode:

Value Behavior
'starttls' Upgrade to TLS after connecting (STARTTLS).
true Implicit TLS from the start of the connection.
false Plain-text connection with no TLS.

Type: { type?: 'plain' | 'login'; username: string; password: string }

SMTP authentication credentials. type defaults to 'plain'.

Type: EmailDkimOptions

DKIM signing options. See Email Types.

Type: string

Hostname sent in the EHLO/HELO greeting. Defaults to the connector’s resolved hostname.

connectionTimeout Optional

Section titled “connectionTimeout ”

Type: number

Milliseconds to wait for the TCP connection to be established.

Type: number

Milliseconds to wait for the server greeting after connecting.

Type: number

Milliseconds of inactivity before the socket is considered timed out.

Type: { maxConnections?: number; maxMessages?: number }

Connection pool settings.

  • maxConnections — maximum concurrent SMTP sessions. Default: 1.
  • maxMessages — retire a session after this many messages. Default: unlimited.

limits.maxAttachmentSize Optional

Section titled “limits.maxAttachmentSize ”

Type: number

Maximum attachment size in bytes.