Skip to content

mailkite/send-email-action

Use this GitHub action with your project
Add this Action to an existing workflow or create a new one
View on Marketplace

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MailKite

Send Email with MailKite

Send email from any GitHub workflow over a domain you verified with MailKite — release notes, CI alerts, and template sends. And with one small relay, trigger workflows from inbound email.

Docs · CLI guide · Receiving · mailkite.dev

The action wraps the official @mailkite/cli (npx --yes @mailkite/cli send); template sends use the mailkite Node SDK. Your API key travels only in the MAILKITE_API_KEY environment variable — never on a command line, never through a shell.

Quick start — email your release notes

Add your MailKite API key (create one at app.mailkite.dev) as the repository secret MAILKITE_API_KEY, then:

name: release-email
on:
  release:
    types: [published]

jobs:
  announce:
    runs-on: ubuntu-latest
    steps:
      - name: Email the release notes
        id: email
        uses: mailkite/send-email-action@v1
        with:
          api-key: ${{ secrets.MAILKITE_API_KEY }}
          from: releases@mail.yourapp.com          # a domain you verified with MailKite
          to: team@yourapp.com
          subject: "${{ github.event.repository.name }} ${{ github.event.release.tag_name }} is out"
          text: ${{ github.event.release.body }}

      - name: Log the message id
        run: echo "sent ${{ steps.email.outputs.message-id }}"

Inputs

Input Required Description
api-key MailKite API key. Store it as a repository secret; it is passed via env, never argv.
from Sender address on a domain you verified with MailKite.
to Recipient address, or a comma-separated list.
subject Required unless template-id supplies one.
html HTML body. Provide html, text, or template-id (html + text together is fine).
text Plain-text body.
template-id Send from a saved template (tpl_…) or a base template (base_…).
template-data JSON object (as a string) filling the template's {{merge_tags}}, e.g. '{"name":"Ann"}'.
reply-to Reply-To address.

Outputs

Output Description
message-id The MailKite message id (msg_…) of the sent email.

Template sends

- uses: mailkite/send-email-action@v1
  with:
    api-key: ${{ secrets.MAILKITE_API_KEY }}
    from: onboarding@mail.yourapp.com
    to: ${{ github.event.client_payload.email }}
    template-id: tpl_welcome123
    template-data: '{"name":"Ann","plan":"pro"}'

Recipe — trigger workflows from inbound email

MailKite receives email for your domain and delivers it as a signed webhook. Point that webhook at a ~30-line relay that verifies the signature and forwards a summary to GitHub's repository_dispatch API — and any email to deploy@mail.yourapp.com (or support@, triage@, …) starts a workflow. Combined with this action, the workflow can email a reply: a full email → workflow → email loop.

1. The relay (a Cloudflare Worker; any host that runs the mailkite SDK works):

// relay.js — verify the MailKite webhook, forward a summary to repository_dispatch
import { MailKite } from "mailkite";

export default {
  async fetch(request, env) {
    if (request.method !== "POST") return new Response("method not allowed", { status: 405 });
    const body = await request.text();
    const sig = request.headers.get("x-mailkite-signature");
    if (!MailKite.verifyWebhook(sig, body, env.MAILKITE_WEBHOOK_SECRET)) {
      return new Response("bad signature", { status: 401 });
    }
    const email = JSON.parse(body); // { id, from: {address}, to: [{address}], subject, text, html, … }
    const res = await fetch(`https://api.github.com/repos/${env.GITHUB_REPO}/dispatches`, {
      method: "POST",
      headers: {
        authorization: `Bearer ${env.GITHUB_TOKEN}`,
        accept: "application/vnd.github+json",
        "content-type": "application/json",
        "user-agent": "mailkite-github-relay",
      },
      // client_payload allows at most 10 top-level properties — send a summary.
      body: JSON.stringify({
        event_type: "inbound-email",
        client_payload: {
          messageId: email.id,
          from: email.from.address,
          to: email.to[0]?.address ?? null,
          subject: email.subject ?? "",
          text: (email.text ?? "").slice(0, 8000),
        },
      }),
    });
    return new Response(res.ok ? "dispatched" : "github error", { status: res.ok ? 200 : 502 });
  },
};
# wrangler.toml
name = "mailkite-github-relay"
main = "relay.js"
compatibility_date = "2026-07-01"
compatibility_flags = ["nodejs_compat"]   # MailKite.verifyWebhook uses node:crypto

[vars]
GITHUB_REPO = "your-org/your-repo"
npm install mailkite wrangler
npx wrangler secret put GITHUB_TOKEN            # fine-grained PAT, Contents: read & write on the repo
npx --yes @mailkite/cli secret get              # your whsec_… webhook signing secret
npx wrangler secret put MAILKITE_WEBHOOK_SECRET
npx wrangler deploy

2. Point your domain's webhook at the relay:

npx --yes @mailkite/cli webhook set <domainId> https://mailkite-github-relay.<account>.workers.dev
npx --yes @mailkite/cli webhook test <domainId>   # sends a signed sample event

3. The workflow it triggers — including an auto-reply through this action:

name: inbound-email
on:
  repository_dispatch:
    types: [inbound-email]

jobs:
  handle:
    runs-on: ubuntu-latest
    steps:
      - name: Do the work
        env: # env indirection — never interpolate email content into shell text
          SUBJECT: ${{ github.event.client_payload.subject }}
          SENDER: ${{ github.event.client_payload.from }}
        run: echo "email from $SENDER — $SUBJECT"

      - name: Reply by email
        uses: mailkite/send-email-action@v1
        with:
          api-key: ${{ secrets.MAILKITE_API_KEY }}
          from: bot@mail.yourapp.com
          to: ${{ github.event.client_payload.from }}
          subject: "Re: ${{ github.event.client_payload.subject }}"
          text: "Got it — the workflow is running: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"

Honest caveats: repository_dispatch only triggers the workflow file on the default branch; client_payload is capped at 10 top-level properties (hence the summary); and email content is untrusted input — keep it in env:/with: and out of inline shell text.

Versioning

Use the major tag (mailkite/send-email-action@v1) or pin an exact release (@v1.0.0). Development happens in the MailKite monorepo; this repo is the published action. Issues: MailKite docs.

License

MIT

About

GitHub Action to send email with MailKite (and trigger workflows from inbound email).

Topics

Resources

License

Stars

0 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors