{
  "slug": "magic-link-email",
  "title": "Magic link sign-in email: template and code",
  "url": "https://www.courier.com/recipes/magic-link-email",
  "markdown": "https://www.courier.com/recipes/magic-link-email.md",
  "stage": "Account and security",
  "purpose": "Sign people in with an emailed link, and never deliver one that has already expired.",
  "summary": "A magic link email signs people in without a password. When someone asks for a sign-in link, it sends one email with a single Sign in button. The link works for 15 minutes, and Courier stops trying to deliver it after that, so nobody gets a link that's already expired.",
  "channels": [
    "email"
  ],
  "shape": "send",
  "shows": [
    "One email with a single Sign in button",
    "A retry window that matches the link's lifetime",
    "A link your app creates and Courier only delivers"
  ],
  "data": [
    {
      "name": "magic_link_url",
      "type": "URL",
      "example": "https://app.acme.com/auth/verify?token=3f9c1e",
      "note": "Your app creates the link and its token"
    }
  ],
  "steps": [
    {
      "step": "1",
      "when": "When someone asks for a sign-in link",
      "channels": "Email",
      "templates": [
        "templates/magic-link.json"
      ]
    }
  ],
  "files": {
    "templates": [
      "templates/magic-link.json"
    ],
    "setup": [
      "setup.ts"
    ],
    "start": [
      "start.ts",
      "start.py"
    ]
  },
  "docs": [
    "https://www.courier.com/docs/send/overview",
    "https://www.courier.com/docs/send/routing",
    "https://www.courier.com/docs/send/statuses"
  ],
  "related_recipes": [
    "https://www.courier.com/recipes/otp-sms-email-fallback",
    "https://www.courier.com/recipes/password-reset-email",
    "https://www.courier.com/recipes/email-verification-reminder-email"
  ],
  "agent_prompt": "Add magic link sign-in emails to this app, sent through Courier: one email with a Sign in button, and no retries after the link expires. Follow the steps at https://www.courier.com/recipes/magic-link-email.md and use the Courier skill for SDK details.\n\n1. Create the template in my Courier workspace by running setup.ts from that page with COURIER_API_KEY from our environment. Save the template ID it prints as COURIER_MAGIC_LINK_TEMPLATE_ID.\n2. Find where this codebase creates a sign-in link and send the email there with the recipe's send code. Pass only magic_link_url. Replace the placeholder product name (Acme) in the template with ours, and make its \"15 minutes\" match the link's real lifetime and the send timeout.\n3. Match this codebase's language, file layout, and error handling. Never hardcode the API key.\n4. When you're done, send one magic link to a test user and show me the rendered email.",
  "status": {
    "state": "passing",
    "last_tested": "2026-10-19"
  }
}
