# Sending Auth emails in the user's language

> SupaHost has one template per Auth email type, with no per-language versions. Three workarounds: bilingual text, localized landing pages, or sending your own sign-in emails with generateLink.

Source: https://supahost.app/kb/custom-emails-by-language · Updated 2026-11-11

There's one template per email type (Confirm sign-up, Magic link, Reset password, Invite, Change email), and templates can't switch language based on the user. The fields accept plain text and four placeholders: `{{ .Email }}`, `{{ .NewEmail }}`, `{{ .Token }}` and `{{ .SiteURL }}`. There's no placeholder for user metadata and no conditional logic. You can still give users a localized experience in one of three ways.

## Option 1: write each template in two languages

If most users speak one of two or three languages, put short versions of each in the same email. Dashboard → your project → **Auth** tab → **Auth emails**, choose the template, and write something like:

```
Subject: Your sign-in link / Votre lien de connexion

Message:
Use the button below to sign in to Bookly. The link works once.
Utilisez le bouton ci-dessous pour vous connecter à Bookly. Le lien ne fonctionne qu'une fois.
```

Keep it short; the Subject is limited to 150 characters and the Button text to 40.

## Option 2: send users to a page in their language

The email stays the same, but where the link lands can follow the user's language. Pass a localized redirect when you start the flow:

```ts
const locale = navigator.language.startsWith("fr") ? "fr" : "en";

await supabase.auth.signInWithOtp({
  email,
  options: {
    emailRedirectTo: `https://bookings.example.com/${locale}/auth/callback`,
    data: { locale }, // saved in user_metadata if this creates the user
  },
});
```

Add `https://bookings.example.com/**` to **Redirect URLs** so every locale path is allowed. Storing `locale` in user metadata lets your app, and any emails you send yourself, use the same language later.

## Option 3: send the email yourself

For fully translated emails, generate the sign-in link on the server and send it through your own email provider. `auth.admin.generateLink()` returns the link and one-time code without sending anything. This Edge Function sends a magic link in English or French:

```ts
import { createClient } from "npm:@supabase/supabase-js@2";

const admin = createClient(Deno.env.get("SUPABASE_URL")!, Deno.env.get("SUPABASE_SERVICE_ROLE_KEY")!, {
  auth: { autoRefreshToken: false, persistSession: false },
});

const copy = {
  en: { subject: "Your Bookly sign-in link", body: "Click to sign in:" },
  fr: { subject: "Votre lien de connexion Bookly", body: "Cliquez pour vous connecter :" },
};

Deno.serve(async (req) => {
  const { email, locale } = await req.json();
  const lang = locale === "fr" ? "fr" : "en";
  const t = copy[lang];

  const { data, error } = await admin.auth.admin.generateLink({
    type: "magiclink",
    email,
    options: { redirectTo: `https://bookings.example.com/${lang}/auth/callback` },
  });
  if (error) return Response.json({ error: "Could not send link" }, { status: 400 });

  await fetch("https://api.resend.com/emails", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${Deno.env.get("RESEND_API_KEY")}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      from: "Bookly <login@bookings.example>",
      to: email,
      subject: t.subject,
      html: `<p>${t.body}</p><p><a href="${data.properties.action_link}">${data.properties.action_link}</a></p>
             <p>Code: <b>${data.properties.email_otp}</b></p>`,
    }),
  });

  return Response.json({ sent: true });
});
```

Things to get right:

- **Never return the link or code in the response.** That would let anyone sign in as any address.
- **Add your own rate limiting**, per address and per IP. Auth's email send limit doesn't apply, because Auth isn't sending.
- Use it for people who already have an account. For new sign-ups, create the user first with `admin.createUser()`, or keep using Auth's Confirm sign-up email.
- Store `RESEND_API_KEY` on the **Functions** tab's **Secrets** card. Any provider with an HTTP API works the same way.

## On SupaHost

Auth's own emails always come from `noreply@supahost.app` with your **App name** as the sender name, and custom SMTP isn't available. Option 3 is also how to send sign-in emails from your own domain.

## Related

- [Auth emails and templates](/docs/auth/email-templates)
- [Example: sending email](/docs/functions/sending-email)
- [Email providers (Resend, Postmark, SendGrid)](/docs/integrations/resend)
- [Site URL and redirect URLs](/docs/auth/redirect-urls)
