You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Node.js使用nodemailer报错transporter.sendMail is not a function如何解决

问题根因

你报transporter.sendMail is not a function错误的核心原因是server.js中变量作用域和代码位置逻辑错误,一共3个核心问题:

  • 文件顶部初始化的全局transporter = '#'是字符串类型,本身不存在sendMail方法
  • 在app.post('/mail')的回调函数内部用let重新定义的局部transporter,只在回调函数内部生效,外部访问不到
  • mailOptions定义、transporter.sendMail调用都写在了app.post路由的外面,服务器启动时就会直接执行这部分代码,不会等到用户提交表单请求时触发,也拿不到用户提交的表单数据
    另外你的前端app.js里fetch的语法也有错误,then方法写在了fetch的配置对象内部,会导致请求异常。

修复后的server.js代码

const express = require('express');
const path = require('path');
const nodemailer = require('nodemailer');
const dotenv = require('dotenv');

dotenv.config();
let initialPath = path.join(__dirname, "public");
let app = express();

app.use(express.static(initialPath));
app.use(express.json());

app.get('/', (req, res) => {
    res.sendFile(path.join(initialPath, "index.html"));
})

app.post('/mail', (req, res) => {
    const { firstname, lastname, email, msg } = req.body;

    // 把transporter定义、mailOptions、sendMail都挪到路由回调内部
    let transporter = nodemailer.createTransport({
        service: 'gmail',
        auth: {
            user: process.env.EMAIL,
            pass: process.env.PASSWORD
        }
    })

    const mailOptions = {
        from: 'yyy@gmail.com',
        to: 'xxx@gmail.com',
        subject: 'Portfolio',
        text: `First name: ${firstname}, \nLast name: ${lastname}, 
        \nEmail: ${email}, \nMessage: ${msg}`
    }

    transporter.sendMail(mailOptions, (err, result) => {
        if (err){
            console.log(err)
            res.json('Oops error occurred')
        } else{
            res.json('thanks for emailing me');
        }
    })
})

app.listen('3000', () => {
    console.log('listening....');
})

修复后的app.js代码

const links = document.querySelectorAll('.link');
        
links.forEach(link => {
    link.addEventListener('click', () =>{
        links.forEach(ele => ele.classList.remove('active'));
        link.classList.add('active');
    })
})

// contact form
const contactBtn = document.querySelector('.contact-btn');
const firstName = document.querySelector('.first-name');
const lastName = document.querySelector('.last-name');
const email = document.querySelector('.email');
const msg = document.querySelector('.message');

contactBtn.addEventListener('click', () => {
    if(firstName.value.length && 
        lastName.value.length && email.value.length && msg.value.length ){
            // 修复fetch的then位置错误
            fetch('/mail', {
                method: 'post',
                headers: new Headers({'Content-Type': 'application/json'}),
                body: JSON.stringify({
                    firstname: firstName.value,
                    lastname: lastName.value,
                    email: email.value,
                    msg: msg.value,
                    
                })
            })
            .then(res => res.json())
            .then(data => {
                alert(data);
            })
        }
})

额外注意事项

如果使用Gmail发信,直接填账号密码会被拦截,需要先开启Google账号的两步验证,然后生成应用专用密码,填到process.env.PASSWORD对应的.env文件里才能正常发信。

内容的提问来源于stack exchange,提问作者IT_TE_42_Naman pandey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.03 04:27:03