如何在Firebase中免费发邮件?使用email-templates遇计费警告未执行
Let's walk through the most likely issues and fixes for your non-executing function, starting with the billing warning you mentioned:
1. Billing Plan Restrictions (Critical First Check)
Firebase's free Spark plan blocks outbound network requests to non-Google services—and SMTP calls to Gmail count as outbound traffic. The billing warning you're seeing is almost certainly related to this restriction, which can cause functions to fail silently before they even attempt to run.
Fix:
Upgrade to the Blaze pay-as-you-go plan (you still get a generous free tier for most low-volume use cases). Without this, any function trying to connect to external SMTP servers will be blocked.
2. Environment Variable Misconfiguration
Your code uses process.env.USER_EMAIL and process.env.USER_PASSWORD, but Firebase Cloud Functions doesn't automatically load local .env variables in production. Local testing might work with dotenv, but deployed functions need proper environment setup.
Fix:
- Option 1 (Firebase Console): Go to your Firebase project > Functions > Configuration > Environment Variables, and add
USER_EMAILandUSER_PASSWORDthere. - Option 2 (CLI): Run these commands in your terminal:
Then update your code to use Firebase's config instead offirebase functions:config:set user.email="your-gmail-address@gmail.com" user.password="your-app-password"process.env:
Important Note: If your Gmail account has 2FA enabled, you must use an App Password (not your regular account password) — create one in your Google Account settings under "Security".auth: { user: functions.config().user.email, pass: functions.config().user.password }
3. Incorrect Nodemailer Transport Settings
Your transport config has a critical mismatch:
secure: false, port: 465
Port 465 is the SSL-only port for SMTP, which requires secure: true. Port 587 uses secure: false with STARTTLS. This contradiction can cause silent connection failures.
Fix:
Update your transport config to one of these valid options:
// Option 1: SSL (port 465) transport: { secure: true, host: "smtp.gmail.com", port: 465, auth: { user: functions.config().user.email, pass: functions.config().user.password } } // Option 2: STARTTLS (port 587) transport: { secure: false, host: "smtp.gmail.com", port: 587, requireTLS: true, // Force STARTTLS handshake auth: { user: functions.config().user.email, pass: functions.config().user.password } }
4. Email Template Path Issues
The path path.resolve(__dirname, "../../src/emails") works locally but may break in production. Firebase packages your functions into a compressed bundle, so the directory structure changes after deployment.
Fix:
- First, add a log to debug the resolved path:
Check the function logs (viaconsole.log("Template root path:", path.resolve(__dirname, "../../src/emails"));firebase functions:logor Google Cloud Console) to see if this path exists in the deployed environment. - Adjust the path to match the deployed structure. For example, if your
emailsfolder is inside thefunctionsdirectory, use:views: { root: path.join(process.cwd(), "src/emails") } - Ensure your template files (e.g.,
sharedSpeech/html.pugorsharedSpeech/html.ejs) aren't excluded by.gitignoreor.firebaseignore— Firebase won't deploy files listed there.
5. Missing Dependencies or Template Engine
email-templates requires a template engine like Pug, EJS, or Handlebars to render your templates. If you haven't installed the engine matching your template files, the function will fail silently.
Fix:
- Install the required template engine (e.g., for Pug):
npm install pug --save - Verify all dependencies are listed in your
package.json(Firebase needs this to install them during deployment).
6. Check Hidden Errors in Logs
Even if the Firebase console shows no obvious errors, detailed logs will reveal what's going wrong.
How to Access Logs:
- Run
firebase functions:log --filter shareSpeechWithEmailin your terminal to see real-time logs for this function. - Or go to the Google Cloud Console > Cloud Functions > Your Function > Logs tab to view full error details, including stack traces.
内容的提问来源于stack exchange,提问作者The.Wolfgang.Grimmer

