A newsletter you run on your own server

Integrations

Mailpiece with Cloudflare Workers

Mailpiece hands each issue to a small relay on a Cloudflare Worker, which passes it to your mail provider's API and remembers what it sent in Workers KV, so a message posted twice is sent once. Your provider's key lives in Cloudflare, not on your server.

With Mailpiece

What you get

  • Issues, test issues, welcome emails and confirmations
  • Any provider with an HTTP API: the Worker below calls Resend, and your agent can change it for another from the relay guide
  • Each issue sent once, however often Mailpiece posts it
  • Your provider's key kept as a Worker secret
  • No SMTP port needed, so it suits a host that blocks one

Set up your provider

Verify your sending domain with the provider and create an API key that can send. For Resend, that is a key with Sending access.

Create the KV namespace

In the Cloudflare dashboard, open Workers KV, choose Create instance and name it, such as mailpiece-sent. The Worker keeps there the Idempotency-Key of each message it has sent, for a week.

Deploy the Worker

In Workers & Pages choose Create application, start from Hello World and deploy it, then choose Edit code, paste the relay below and deploy again. Its address is shown on the Worker's page, such as https://mailpiece-relay.example.workers.dev.

A message whose key the Worker has already sent is answered as sent and not sent again. KV can take up to a minute to show a new key in other locations, so the Worker also hands the key to Resend, which keeps it for 24 hours.

// A week: Mailpiece stops posting a message once it is answered as sent.
const KEPT_FOR = 7 * 24 * 60 * 60

const address = (email, name) => name ? `${JSON.stringify(name)} <${email}>` : email

export default {
  async fetch(request, env) {
    if (request.headers.get("Authorization") !== `Bearer ${env.RELAY_TOKEN}`) {
      return new Response("Unauthorized", { status: 401 })
    }

    const key = request.headers.get("Idempotency-Key")
    if (key) {
      const sent = await env.SENT.get(key)
      if (sent !== null) return Response.json({ message_id: sent })
    }

    const message = await request.json()
    const headers = { ...message.headers }
    if (message.list_unsubscribe) {
      headers["List-Unsubscribe"] = message.list_unsubscribe
      headers["List-Unsubscribe-Post"] = "List-Unsubscribe=One-Click"
    }

    const response = await fetch("https://api.resend.com/emails", {
      method: "POST",
      headers: {
        "Authorization": `Bearer ${env.RESEND_API_KEY}`,
        "Content-Type": "application/json",
        ...(key && { "Idempotency-Key": key })
      },
      body: JSON.stringify({
        from: address(message.from, message.from_name),
        to: message.to,
        cc: message.cc,
        bcc: message.bcc,
        reply_to: message.reply_to && address(message.reply_to, message.reply_to_name),
        subject: message.subject,
        html: message.html,
        text: message.text,
        headers,
        tags: message.tags?.map(name => ({ name, value: "true" }))
      })
    })
    if (!response.ok) return new Response(await response.text(), { status: response.status })

    const { id } = await response.json()
    if (key) await env.SENT.put(key, id, { expirationTtl: KEPT_FOR })
    return Response.json({ message_id: id })
  }
}

Bind the namespace and add the secrets

On the Worker's Bindings tab choose Add binding, then KV namespace, name the variable SENT and pick your namespace. Under Settings › Variables and Secrets add two secrets and deploy: RELAY_TOKEN, a long random string you choose, and RESEND_API_KEY, your provider's key. The Worker reads them as env.SENT, env.RELAY_TOKEN and env.RESEND_API_KEY.

Set the outgoing mail

In Mailpiece, on Settings › Outgoing mail, set up a relay: the Relay address is the Worker's, and the Token the same string as the Worker's RELAY_TOKEN. Every setting is in the mail guide.

# Or from the CLI
mailpiece settings sending relay update --url https://mailpiece-relay.example.workers.dev --token RELAY_TOKEN

Send a test issue

Set a from address on your verified domain in Settings › Sending and send a test issue from any post. If it does not arrive, open the Worker's logs in the dashboard, then your provider's email log.

Set it up this afternoon

Install Mailpiece on a server, connect Cloudflare Workers, and send your next issue.

Install Mailpiece