Docs / Firebase

Firebase Authentication custom SMTP

Firebase Authentication emails users to verify their address, reset a password, confirm an email change and flag a newly added second factor. By default those messages come from a firebaseapp.com address and are sent by Google. Custom SMTP makes them come from your own domain, signed with its DKIM key — which is what gets them out of spam and makes them look like they come from you.

✓
You can get them on the token management page. For security reasons, a token is shown only once — at the moment it is created.

SMTP connection settings

SettingValue
SMTP hostsmtp.postwing.app
Port587
EncryptionSTARTTLS (the connection is upgraded to TLS before login)
UsernameThe login of an SMTP token for your domain
PasswordThe password of that token — shown once, when the token is created
ℹ
Every mode is also available on a high port: 8465 (SSL/TLS), 8587 (STARTTLS) and 8025 (plain). Many hosting providers and clouds block outbound 25, 465 and 587 — if the connection times out, switch to the matching high port.

Step 1 — turn on SMTP settings

In the Firebase console, open Authentication → Templates, choose SMTP settings, enable it and fill in:

FieldValue
Sender addressnoreply@your-domain.com — on your verified domain
SMTP server hostsmtp.postwing.app
SMTP server port587
SMTP account usernameThe login of an SMTP token for your domain
SMTP account passwordThat token's password
SMTP security modeSTARTTLS
⚠
STARTTLS goes with port 587; SSL goes with port 465. Any other combination fails before the login is even tried.

Step 2 — review the templates

Still on the Templates tab, open each email type with the pencil icon. You can set the sender name, reply-to address and subject for all of them, and the message body for password reset. The placeholders %LINK%, %EMAIL%, %NEW_EMAIL%, %APP_NAME% and %DISPLAY_NAME% are filled in per message.

%APP_NAME% is the project's public-facing name from project settings. Make it the name users know you by — a verification email from "project-1234" reads like phishing.

Configure it with the API

The same setting through the Identity Toolkit admin API, for scripted or repeatable setups:

Identity Toolkit admin API
PROJECT_ID=your-project-id

curl -X PATCH \
  "https://identitytoolkit.googleapis.com/admin/v2/projects/$PROJECT_ID/config?updateMask=notification.sendEmail.method,notification.sendEmail.smtp" \
  -H "Authorization: Bearer $(gcloud auth print-access-token)" \
  -H "X-Goog-User-Project: $PROJECT_ID" \
  -H "Content-Type: application/json" \
  -d '{
    "notification": {
      "sendEmail": {
        "method": "CUSTOM_SMTP",
        "smtp": {
          "senderEmail": "noreply@your-domain.com",
          "host": "smtp.postwing.app",
          "port": 587,
          "username": "token-login@your-domain.com",
          "password": "your-token-password",
          "securityMode": "START_TLS"
        }
      }
    }
  }'

Fully custom auth emails

When the template editor is not enough — your own layout, your own language per user, the email sent from your backend — let the Admin SDK generate the action link and send the message yourself:

sendPasswordReset.js
// Node.js backend or Cloud Function: your own email around Firebase's action link
import { initializeApp } from "firebase-admin/app";
import { getAuth } from "firebase-admin/auth";
import nodemailer from "nodemailer";

initializeApp();

const transporter = nodemailer.createTransport({
  host: "smtp.postwing.app",
  port: 587,
  secure: false, // STARTTLS
  auth: { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS },
});

export async function sendPasswordReset(email) {
  const link = await getAuth().generatePasswordResetLink(email, {
    url: "https://your-domain.com/login", // where the user lands afterwards
  });

  await transporter.sendMail({
    from: "Acme <noreply@your-domain.com>",
    to: email,
    subject: "Reset your Acme password",
    text: "Reset your password: " + link,
    html: '<p><a href="' + link + '">Reset your password</a></p>',
  });
}

generateEmailVerificationLink and generateSignInWithEmailLink work the same way.

For app emails triggered from Firestore, Firebase's Trigger Email from Firestore extension sends every document added to a collection through SMTP. Leave the password out of the connection URI and put it in the separate password field. The login is an email address, so its @ is written as %40:

Extension parameters
# Trigger Email from Firestore extension
SMTP connection URI:   smtp://token-login%40your-domain.com@smtp.postwing.app:587
SMTP password:         your-token-password
Default FROM address:  Acme <noreply@your-domain.com>

Send a test email

Trigger a password reset for a test account from your app, or from the user list under Authentication → Users. Check the received message's From address and headers: it should show your domain, with DKIM passing.

Troubleshooting

SymptomCause and fix
Emails still come from firebaseapp.comSMTP settings are not enabled, or were not saved.
Emails stop arriving after enabling SMTP Wrong credentials, or the security mode does not match the port.
Verification email body cannot be edited Firebase allows it only for password reset. Send your own email with an Admin SDK link.
Cloud Function times out connecting Port 25 is blocked on Google Cloud. Use 587 or 465.
Mail goes to spam Sender address is not on your verified domain.

Frequently asked questions

Does Firebase Authentication support a custom SMTP server?

Yes. In the Firebase console, Authentication → Templates has an SMTP settings section: enable it and enter the sender address, host, port, username, password and security mode. From then on, Firebase's account emails are sent through your server instead of Google's default sender.

Which Firebase emails go through custom SMTP?

The account management emails on the Templates tab: email address verification, password reset, email address change and the notice sent when a second factor is added. SMS messages are unaffected, and so is anything your own code sends.

Should the SMTP security mode be STARTTLS or SSL?

STARTTLS with port 587, or SSL with port 465. A mismatched pair fails the handshake before authentication even starts.

Can I change the text of Firebase's verification email?

Only partly. Firebase lets you edit the sender name, reply-to and subject of every template, but the message body only for password reset — a restriction meant to keep the templates from being used for spam. For full control, generate the action link with the Admin SDK and send your own email, as shown above.

Why do the links in Firebase emails still point to firebaseapp.com?

Custom SMTP changes who sends the email, not where its links go. The links lead to Firebase's default action handler. To use your own page, set a custom action URL in the template editor and handle the action codes there.

Can Cloud Functions send email over SMTP?

Yes, on port 587 or 465 — Google Cloud blocks outbound port 25, so never use that one. Cloud Functions can also call the REST API over HTTPS, which avoids SMTP entirely.

Next steps