Skip to content

E-mailed invitations

kubelatch can send the one-time links of an invitation or an access reset by e-mail, through Resend, instead of showing them to you to copy. This page says how to set Resend up, what to configure in kubelatch, what you should know about security and what to do when an e-mail doesn't arrive.

What it does

  • It's a Pro feature, including the trial and the grace period. In Free the option is shown disabled and marked Pro; copying the link keeps working in every edition.
  • It covers the two kinds of link an administrator issues for a person: the invitation of a new account (72 hours) and the reset or linking link of an existing one (24 hours). See Users and bots.
  • You choose, each time, between sending by e-mail and copying the link. Not both: with e-mail, kubelatch never shows you the link, so only one live copy exists, in the person's mailbox.
  • The e-mail goes only to the address on the account, never to a free-form one. The form names that address before you send, and the audit records it.
  • If the e-mail doesn't arrive, you resend it or copy a new link from the person's row or page. Either cancels the previous one.

Set up Resend

  1. Create a Resend account and verify the sending domain (the DNS records Resend asks for). Send from a domain you control, such as mail.example.com.
  2. Create an API key with the Sending access permission, restricted to that domain. Don't use a full-access key: if the key leaks, the damage is limited to e-mails from that domain.
  3. Keep click tracking and open tracking off on the domain. They're off by default; leave them that way. Tracking rewrites the links in the message so they pass through Resend's redirector, and the token of the invitation would travel through Resend's servers.

kubelatch only talks to https://api.resend.com: the address is fixed and can't be changed, and there's no SMTP.

Configure kubelatch

Two environment variables, listed in Configuration:

Variable What it is
KUBELATCH_RESEND_API_KEY The Resend API key. A secret: it goes in the kubelatch-secrets Secret.
KUBELATCH_MAIL_FROM The sender, on the verified domain: noreply@example.com or kubelatch <noreply@example.com>. Required when there's a key.

With the Helm chart (Install):

  • Set mail.from in your values; the chart turns it into KUBELATCH_MAIL_FROM.
  • Put the key in the Secret: secrets.env.KUBELATCH_RESEND_API_KEY, or the KUBELATCH_RESEND_API_KEY field of your secrets.existingSecret.
mail:
  from: "kubelatch <noreply@example.com>"

Without mail.from the chart defines nothing and everything works as before. The variables are only read at startup: after changing them, restart the pods.

kubelatch validates them when it starts. A key without a sender, or a KUBELATCH_MAIL_FROM that isn't a valid address, stops the server, and the log says which value is wrong, like any other bad variable. The key never appears in logs, errors, the database or the API.

When both are set, the creation form offers Send by e-mail, and it's the default. With Pro but no Resend, the option says Resend isn't configured on the server and links here.

Security notes

  • Resend keeps the content of what it sends for about 30 days, and its dashboard shows it. Anyone with access to that account's Resend dashboard can read the invitations and resets that haven't been used yet, and use them. Treat access to the dashboard as the power to redeem pending invitations: give it to as few people as you can, with the same care as an administrator account.
  • The links die fast. They work once; an invitation lasts 72 hours and a reset 24. Using one, issuing another for the same person or letting it expire ends it, so what stays in Resend's history is useless after that. Issuing a new link, by e-mail or by copy, cancels the pending ones.
  • The token travels in the URL fragment (after the #), which browsers never send over HTTP. Mail scanners that open the link don't consume it: only the person pressing the button on the page does.
  • Limits per hour, so a stolen administrator account can't use kubelatch as a spam relay: 3 e-mails per account and 20 per administrator. Every attempt counts, a failed one too. Past them, the answer is 429 mail.rate_limited.
  • The message names who invites, the real host of your kubelatch and the expiry, tells the reader to check that the link starts with your base URL, and never asks for a password. It has no remote images and no tracking.
  • Audit. Each send writes link.email_sent (the purpose of the link, the address and Resend's message id) and each failure link.email_failed (with the HTTP status Resend answered), next to the usual user.create or link.reset, which also say the delivery was by e-mail. They're in Audit and retention. Neither holds the link or the token.

Troubleshooting

What you see Cause and what to do
403 edition.feature The instance isn't Pro. Install a key (Editions and license) or copy the link instead.
409 mail.not_configured The server has no Resend key or sender. Configure it as above and restart.
422 mail.no_address The account has no e-mail. Add one in the form, or copy the link.
422 mail.invalid_address The e-mail of the account isn't a single valid address. Correct it.
429 mail.rate_limited Past 3 e-mails per account or 20 per administrator in the last hour. Wait, or copy the link.
502 mail.failed Resend refused the invitation. The account exists, and the link is already cancelled. The message says the status Resend returned. Resend or copy a new link from its row.
502 mail.unreachable Resend didn't answer (a network error or a timeout). The account exists, and the link is already cancelled. Check that the server reaches api.resend.com, then resend or copy a new link.
502 mail.failed_reset, 502 mail.unreachable_reset The same for a reset: the link is already cancelled and the person's sessions are already closed. Resend or copy a new link from the account's page.

For 502 mail.failed and mail.failed_reset, the status says where to look: 401 or 403 is a wrong or too narrow key, or a sender outside the verified domain; 422 is an address Resend rejects; 429 is Resend's own limit; 5xx is Resend being down. The reason is in link.email_failed, in Audit.

The e-mail didn't arrive. kubelatch only knows that Resend accepted it. Look for the message in Resend's Emails log: if it says delivered, the problem is on the person's side (the spam folder, a filtering gateway); if it says bounced, the address is wrong. Then resend it (Resend invitation by e-mail in the row, or Reset access on the account's page) or Copy a new link; both cancel the previous one.