Docs / Integrations / DevOps

DevOps & Infrastructure

Send deployment notifications, on-call alerts, and infra change confirmations from your CI/CD pipelines, IaC tools, and container orchestration.

Machine translation available — choose your language in the top bar.

Each integration lives under the integrations/ directory. Drop in your MAILGRID_API_KEY secret, wire up the step or resource, and every deploy, apply, or helm upgrade can notify your team without leaving the pipeline.

GitHub Actions

Located at integrations/github-action/. A native Node 20 action — no external dependencies, just action.yml and a small TypeScript runner that calls the InboxOS API.

action.yml inputs

InputRequiredDescription
api-keyYesYour Mailgrid API key — store as a repo secret
fromYesVerified sender address
toYesRecipient address (comma-separated for multiple)
subjectYesEmail subject line
bodyYesPlain-text or HTML body

Complete workflow example

.github/workflows/notify.yml
name: Deploy & Notify

on:
  push:
    branches: [main]
  release:
    types: [published]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Build & deploy
        run: npm ci && npm run deploy

      - name: Notify on success
        if: success()
        uses: mailgrid/notify-action@v1
        with:
          api-key: ${{ secrets.MAILGRID_API_KEY }}
          from: deploys@yourapp.com
          to: team@yourapp.com
          subject: "Deployed ${{ github.ref_name }} to production"
          body: |
            Deployment succeeded.

            Commit: ${{ github.sha }}
            Author: ${{ github.actor }}
            Workflow: ${{ github.workflow }}

      - name: Notify on failure
        if: failure()
        uses: mailgrid/notify-action@v1
        with:
          api-key: ${{ secrets.MAILGRID_API_KEY }}
          from: deploys@yourapp.com
          to: oncall@yourapp.com
          subject: "FAILED: ${{ github.ref_name }} deployment"
          body: |
            Deployment failed — immediate attention required.

            Commit: ${{ github.sha }}
            Author: ${{ github.actor }}
            Run: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
Release notifications

Trigger on release: published to email your subscriber list every time a GitHub release is cut. Combine with the Templates API to render a proper changelog email.

GitLab CI

Located at integrations/gitlab-ci/. A curl-based job definition — no additional runners or plugins needed. Add the snippet to any .gitlab-ci.yml stage.

.gitlab-ci.yml
stages:
  - build
  - deploy
  - notify

notify-deploy:
  stage: notify
  image: curlimages/curl:latest
  when: on_success
  script:
    - |
      curl -s -X POST https://api.mailgrid.space/api/emails \
        -H "Authorization: Bearer $MAILGRID_API_KEY" \
        -H "Content-Type: application/json" \
        -d "{
          \"from\":    \"deploys@yourapp.com\",
          \"to\":      \"team@yourapp.com\",
          \"subject\": \"Deployed ${CI_COMMIT_REF_NAME} — pipeline #${CI_PIPELINE_ID}\",
          \"text\":    \"Commit ${CI_COMMIT_SHORT_SHA} by ${GITLAB_USER_LOGIN} deployed successfully.\n\nPipeline: ${CI_PIPELINE_URL}\"
        }"

notify-failure:
  stage: notify
  image: curlimages/curl:latest
  when: on_failure
  script:
    - |
      curl -s -X POST https://api.mailgrid.space/api/emails \
        -H "Authorization: Bearer $MAILGRID_API_KEY" \
        -H "Content-Type: application/json" \
        -d "{
          \"from\":    \"deploys@yourapp.com\",
          \"to\":      \"oncall@yourapp.com\",
          \"subject\": \"FAILED: pipeline #${CI_PIPELINE_ID} on ${CI_COMMIT_REF_NAME}\",
          \"text\":    \"Pipeline failed.\n\nCommit: ${CI_COMMIT_SHORT_SHA}\nAuthor: ${GITLAB_USER_LOGIN}\nURL: ${CI_PIPELINE_URL}\"
        }"

Set MAILGRID_API_KEY under Settings → CI/CD → Variables with the "Masked" flag so it never appears in job logs.

Netlify

Located at integrations/netlify/. A Netlify Build Plugin that hooks into onSuccess and onError lifecycle events to send deployment emails without any custom functions.

netlify.toml plugin config

netlify.toml
[[plugins]]
  package = "@mailgrid/netlify-plugin"

  [plugins.inputs]
    from    = "deploys@yourapp.com"
    to      = "team@yourapp.com"
    success_subject = "Netlify deploy succeeded — {{BRANCH}}"
    failure_subject = "Netlify deploy FAILED — {{BRANCH}}"

Plugin lifecycle hooks

integrations/netlify/index.js
module.exports = {
  async onSuccess({ inputs, utils }) {
    await sendEmail({
      apiKey:  process.env.MAILGRID_API_KEY,
      from:    inputs.from,
      to:      inputs.to,
      subject: inputs.success_subject
        .replace("{{BRANCH}}", process.env.BRANCH),
      text: [
        `Deploy ID: ${process.env.DEPLOY_ID}`,
        `Branch:    ${process.env.BRANCH}`,
        `URL:       ${process.env.DEPLOY_URL}`,
        `Context:   ${process.env.CONTEXT}`,
      ].join("\n"),
    });
  },

  async onError({ inputs, error, utils }) {
    await sendEmail({
      apiKey:  process.env.MAILGRID_API_KEY,
      from:    inputs.from,
      to:      inputs.to,
      subject: inputs.failure_subject
        .replace("{{BRANCH}}", process.env.BRANCH),
      text: `Build failed: ${error.message}\n\nDeploy ID: ${process.env.DEPLOY_ID}`,
    });
  },
};

Add MAILGRID_API_KEY as an environment variable in the Netlify UI under Site settings → Environment variables.

Vercel

Located at integrations/vercel/. A Vercel integration manifest that installs directly from the Vercel Marketplace. After installation it automatically injects MAILGRID_API_KEY as an environment variable into every project in your Vercel team.

integration.json

integrations/vercel/integration.json
{
  "name":        "Mailgrid",
  "slug":        "mailgrid",
  "description": "Transactional email via AWS SES for Vercel projects",
  "scopes": ["read-write:environment-variables"],
  "ui": {
    "redirect_login_page": "https://api.mailgrid.space/oauth/vercel/callback"
  },
  "env": [
    {
      "key":         "MAILGRID_API_KEY",
      "description": "Mailgrid API key injected by the integration",
      "visible":     false
    },
    {
      "key":         "MAILGRID_FROM_EMAIL",
      "description": "Default verified sender address",
      "visible":     true
    }
  ]
}

Once installed, call POST https://api.mailgrid.space/api/emails directly from your Vercel API routes using process.env.MAILGRID_API_KEY — no additional configuration needed.

Cloudflare Pages

Located at integrations/cloudflare-pages/. A Pages Functions proxy at /api/mailgrid/[[path]].js. Client-side code calls /api/mailgrid/emails; the Function forwards the request to InboxOS server-side, keeping MAILGRID_API_KEY out of the browser bundle.

functions/api/mailgrid/[[path]].js
export async function onRequest(context) {
  const { request, env, params } = context;
  const path     = (params.path ?? []).join("/");
  const upstream = `https://api.mailgrid.space/api/${path}`;

  // Forward the request with the server-side API key
  const proxied = new Request(upstream, {
    method:  request.method,
    headers: new Headers({
      "Authorization":  `Bearer ${env.MAILGRID_API_KEY}`,
      "Content-Type":   "application/json",
    }),
    body:    request.method !== "GET" ? request.body : undefined,
  });

  const response = await fetch(proxied);
  return new Response(response.body, {
    status:  response.status,
    headers: { "Content-Type": "application/json" },
  });
}

Set MAILGRID_API_KEY in your Pages project under Settings → Environment variables → Production. The proxy accepts the same JSON body as the direct API.

Terraform

Located at integrations/terraform/. Uses the hashicorp/http provider to call the Mailgrid API as part of your infrastructure apply — verifies a domain and sends a test email to confirm the stack is live.

integrations/terraform/main.tf
terraform {
  required_providers {
    http = {
      source  = "hashicorp/http"
      version = "~> 3.0"
    }
  }
}

variable "mailgrid_api_key" {
  type      = string
  sensitive = true
}

# Verify sending domain
resource "terraform_data" "domain_verify" {
  provisioner "local-exec" {
    command = <<-EOT
      curl -s -X POST https://api.mailgrid.space/api/domains/verify \
        -H "Authorization: Bearer ${var.mailgrid_api_key}" \
        -H "Content-Type: application/json" \
        -d '{"domain": "yourapp.com"}'
    EOT
  }
}

# Send post-apply confirmation email
resource "terraform_data" "deploy_notification" {
  depends_on = [terraform_data.domain_verify]

  provisioner "local-exec" {
    command = <<-EOT
      curl -s -X POST https://api.mailgrid.space/api/emails \
        -H "Authorization: Bearer ${var.mailgrid_api_key}" \
        -H "Content-Type: application/json" \
        -d '{
          "from":    "infra@yourapp.com",
          "to":      "team@yourapp.com",
          "subject": "Terraform apply complete",
          "text":    "Infrastructure stack applied successfully."
        }'
    EOT
  }
}

Pass the API key via TF_VAR_mailgrid_api_key or a .tfvars file — never commit it to version control.

Pulumi

Located at integrations/pulumi/. A TypeScript dynamic resource — MailgridDomain — that registers a verified sending domain as a first-class Pulumi resource and surfaces the DKIM CNAME records as stack outputs.

integrations/pulumi/mailgrid.ts
import * as pulumi from "@pulumi/pulumi";

class MailgridDomainProvider implements pulumi.dynamic.ResourceProvider {
  async create(inputs: { domain: string; apiKey: string }) {
    const res = await fetch(
      "https://api.mailgrid.space/api/domains/verify",
      {
        method:  "POST",
        headers: {
          "Authorization": `Bearer ${inputs.apiKey}`,
          "Content-Type":  "application/json",
        },
        body: JSON.stringify({ domain: inputs.domain }),
      },
    );
    const data = await res.json();
    return {
      id:   inputs.domain,
      outs: {
        domain:     inputs.domain,
        dkimTokens: data.data?.dkimTokens ?? [],
        status:     data.data?.status ?? "pending",
      },
    };
  }
}

export class MailgridDomain extends pulumi.dynamic.Resource {
  public readonly dkimTokens!: pulumi.Output<string[]>;
  public readonly status!:     pulumi.Output<string>;

  constructor(name: string, args: { domain: pulumi.Input<string>; apiKey: pulumi.Input<string> }, opts?: pulumi.CustomResourceOptions) {
    super(new MailgridDomainProvider(), name, { ...args, dkimTokens: undefined, status: undefined }, opts);
  }
}

// Usage in your Pulumi stack
const domain = new MailgridDomain("sending-domain", {
  domain: "yourapp.com",
  apiKey: new pulumi.Config().requireSecret("mailgridApiKey"),
});

export const dkimTokens = domain.dkimTokens;
export const verifyStatus = domain.status;

Run pulumi stack output dkimTokens after apply to get the three CNAME values to add to DNS.

Kubernetes / Helm

Located at integrations/kubernetes/. A Helm chart named mailgrid-notify that installs a post-install and post-upgrade Job hook. The Job runs a one-shot container that calls the InboxOS API to confirm each deployment.

Install or upgrade

terminal
helm upgrade --install mailgrid-notify \
  integrations/kubernetes/chart \
  --namespace yourapp \
  --set mailgrid.apiKey=$MAILGRID_API_KEY \
  --set mailgrid.from=deploys@yourapp.com \
  --set mailgrid.to=team@yourapp.com \
  --set mailgrid.subject="Helm release {{ .Release.Name }} deployed to {{ .Release.Namespace }}"

Hook Job template

integrations/kubernetes/chart/templates/notify-job.yaml
apiVersion: batch/v1
kind: Job
metadata:
  name: "{{ .Release.Name }}-notify"
  annotations:
    "helm.sh/hook": post-install,post-upgrade
    "helm.sh/hook-weight": "0"
    "helm.sh/hook-delete-policy": hook-succeeded
spec:
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: notify
          image: curlimages/curl:latest
          command:
            - sh
            - -c
            - |
              curl -s -X POST https://api.mailgrid.space/api/emails \
                -H "Authorization: Bearer $MAILGRID_API_KEY" \
                -H "Content-Type: application/json" \
                -d "{\"from\":\"$(MAILGRID_FROM)\",\"to\":\"$(MAILGRID_TO)\",
                     \"subject\":\"{{ .Values.mailgrid.subject }}\",
                     \"text\":\"Release {{ .Release.Name }} — revision {{ .Release.Revision }}\"}"
          env:
            - name: MAILGRID_API_KEY
              valueFrom:
                secretKeyRef:
                  name: mailgrid-secret
                  key: api-key
            - name: MAILGRID_FROM
              value: "{{ .Values.mailgrid.from }}"
            - name: MAILGRID_TO
              value: "{{ .Values.mailgrid.to }}"
Store the API key as a Kubernetes Secret

Create the secret before installing the chart: kubectl create secret generic mailgrid-secret --from-literal=api-key=$MAILGRID_API_KEY -n yourapp

AWS CDK

Located at integrations/aws-cdk/. An L3 construct called MailgridDeploy that wires CodeDeploy lifecycle hooks to a Lambda function which calls the InboxOS API on deployment success or failure.

integrations/aws-cdk/mailgrid-deploy.ts
import * as cdk      from "aws-cdk-lib";
import * as lambda  from "aws-cdk-lib/aws-lambda";
import * as ssm     from "aws-cdk-lib/aws-ssm";
import { Construct } from "constructs";

export class MailgridDeploy extends Construct {
  constructor(scope: Construct, id: string, props: {
    from:       string;
    to:         string;
    appName:    string;
    apiKeyPath: string; // SSM SecureString parameter path
  }) {
    super(scope, id);

    const apiKey = ssm.StringParameter.valueForSecureStringParameter(
      this, "ApiKey", props.apiKeyPath,
    );

    const notifyFn = new lambda.Function(this, "NotifyFn", {
      runtime: lambda.Runtime.NODEJS_20_X,
      handler: "index.handler",
      code:    lambda.Code.fromAsset("integrations/aws-cdk/lambda"),
      environment: {
        MAILGRID_API_KEY: apiKey,
        FROM_EMAIL:       props.from,
        TO_EMAIL:         props.to,
        APP_NAME:         props.appName,
      },
    });
  }
}

// Stack usage
const app   = new cdk.App();
const stack = new cdk.Stack(app, "MyAppStack");

new MailgridDeploy(stack, "DeployNotify", {
  from:       "deploys@yourapp.com",
  to:         "team@yourapp.com",
  appName:    "MyApp",
  apiKeyPath: "/prod/mailgrid/api-key",
});

Store the Mailgrid API key in AWS SSM Parameter Store as a SecureString before running cdk deploy:

terminal
aws ssm put-parameter \
  --name /prod/mailgrid/api-key \
  --type SecureString \
  --value $MAILGRID_API_KEY

cdk deploy MyAppStack

Docker

Located at integrations/docker/. An SMTP sidecar pattern for applications that only speak SMTP and cannot make HTTP API calls directly. A lightweight relay container accepts SMTP on port 587 and forwards it to InboxOS.

integrations/docker/docker-compose.example.yml
version: "3.9"

services:
  app:
    image: yourapp:latest
    environment:
      SMTP_HOST: mailgrid-relay
      SMTP_PORT: "587"
      SMTP_USER: apikey
      SMTP_PASS: "${MAILGRID_API_KEY}"
    depends_on:
      - mailgrid-relay

  mailgrid-relay:
    image: mailgrid/smtp-relay:latest
    environment:
      MAILGRID_API_KEY:  "${MAILGRID_API_KEY}"
      RELAY_LISTEN_PORT: "587"
      ALLOWED_NETWORKS:  "172.16.0.0/12"
    ports:
      - "127.0.0.1:587:587"  # bind to loopback only
    restart: unless-stopped

  # Optional: health-check container that sends a test email on startup
  smoke-test:
    image: curlimages/curl:latest
    depends_on:
      - mailgrid-relay
    entrypoint:
      - sh
      - -c
      - |
        sleep 3
        curl -s -X POST https://api.mailgrid.space/api/emails \
          -H "Authorization: Bearer $MAILGRID_API_KEY" \
          -H "Content-Type: application/json" \
          -d '{"from":"deploys@yourapp.com","to":"team@yourapp.com",
               "subject":"Container stack started","text":"Compose stack is up."}'
    environment:
      MAILGRID_API_KEY: "${MAILGRID_API_KEY}"
    restart: "no"
Never bind the relay to 0.0.0.0 in production

The SMTP relay accepts unauthenticated connections from ALLOWED_NETWORKS. Bind the port to 127.0.0.1 or a private Docker network — never to all interfaces on a public host.

Quick reference

Tool Integration path Trigger
GitHub Actions integrations/github-action/ on: push, on: release
GitLab CI integrations/gitlab-ci/ Pipeline stage (when: on_success/on_failure)
Netlify integrations/netlify/ Build plugin onSuccess / onError
Vercel integrations/vercel/ Marketplace integration, env var injection
Cloudflare Pages integrations/cloudflare-pages/ Pages Function proxy
Terraform integrations/terraform/ terraform apply local-exec provisioner
Pulumi integrations/pulumi/ Dynamic resource on pulumi up
Kubernetes / Helm integrations/kubernetes/ Post-install / post-upgrade Job hook
AWS CDK integrations/aws-cdk/ L3 construct, CodeDeploy Lambda hook
Docker integrations/docker/ SMTP sidecar via Compose