如何使用 Lambda 函数将 nodemailer 连接到 Vue.js 和 Netlify 应用程序

How to connect nodemailer to a Vue.js and Netlify app using Lambda Functions

我在 Netlify 上有一个用 Vue.js 构建的静态网站,我有一个特定的需要来捕获从联系路由发送的 x-www-form-urlencoded 数据。

因为它是一个 spa 和动态呈现的表单,所以我在 index.html 中添加了它(预呈现并允许 Netlify 在加载时查看表单)

public/index.html & src/views/Contact.vue

<form 
  netlify-honeypot="bot-field"
  name="contact"
  data-netlify="true" hidden>

    <input name="bot-field" />
    <input type="text" name="name" />
    <input type="email" name="email" />
    <input type="text" name="subject" />
    <textarea rows="5" name="message"></textarea>

</form>

联系人视图:

<form
  netlify-honeypot="bot-field"
  name="contact" method="post"
  data-netlify="true"
  @submit.prevent="handleSubmit">

  <input type="hidden" name="form-name" value="contact" />
    <p style="opacity: 0;">
      <label>Don’t fill this out if you're human: <input name="bot-field" /></label>
    </p>
    <p>
      <label>Your Name: <input v-model="form.name" type="text" name="name" /></label>
    </p>
    <p>
      <label>Your Email: <input v-model="form.email" type="email" name="email" /></label>
    </p>
    <p>
      <label>Your Subject: <input v-model="form.subject" type="text" name="subject" /></label>
    </p>
    <p>
      <label>Message: <textarea v-model="form.message" rows="5" name="message"></textarea></label>
    </p>
    <p>
      <button>Send</button>
    </p>

</form>

对组件中的数据属性进行建模,POST关闭数据的方法如下:

export default {
  name: 'contact',
  data: () => ({
    form: {
      name: '',
      email: '',
      subject: '',
      message: '',
    },
  }),
  methods: {
    encode (data) {
      return Object.keys(data)
        .map(
          key => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`,
        )
        .join('&');
    },
    handleSubmit () {
      const axiosConfig = {
        header: { 'Content-Type': 'application/x-www-form-urlencoded' },
      };
      axios.post(
        '/',
        this.encode({
          'form-name': 'contact',
          ...this.form,
        }),
        axiosConfig,
      )
        .then(() => console.log('success'))
        .catch(e => console.error(e));
    },
  },
};

系统的下一部分是 Netlify 的 lambda 函数 运行。每次应用程序收到表单提交时,Netlify 都允许 submission-created 函数。您所要做的就是在项目的根目录中创建一个目录,其中包含 submission-created.js 文件。此目录需要在 netlify.toml 中指定,以便 Netlify 知道在哪里寻找您的函数。

另一个需要注意的是,如果您的函数需要依赖项,则需要将包含 node_modules 的文件夹压缩。我在 package.json 中使用 bestzip 依赖项自动执行此操作。

package.json

"scripts": {
    "serve": "vue-cli-service serve",
    "build": "vue-cli-service build",
    "lint": "vue-cli-service lint",
    "zip": "cd functions/submission-created && bestzip ../../functions-build/submission-created.zip *",
    "clean": "rm -rf functions-build && mkdir functions-build",
    "prebuild": "npm run clean && npm run zip"
}

如您所见,我处理这个问题的方法是在 functions/submission-created/submission-created.js 中编写函数的源代码我还有一个 functions-build 目录,它是 netlify.toml 中指定的目录,其中将包含压缩的提交创建文件夹。

基本上,我 npm init -y functions/submission-created 目录和 npm install nodemailer,当预置 运行s 时,它会删除当前的函数构建并重新创建它,然后将函数及其依赖项压缩到目录中。

这是netlify.toml

[build]
  functions = "./functions-build"

最后,重要代码所在的是 submission-created.js 文件:


exports.handler = function(event, context, callback) {
  const nodemailer = require('nodemailer');
  const querystring = require('querystring');
  const payload = querystring.parse(event.body);
  const { name, email, subject, message } = payload;

  // create reusable transporter object using the default SMTP transport
  let transporter = nodemailer.createTransport({
    host: "xxx",
    port: 587,
    secure: false, // true for 465, false for other ports
    auth: {
      user: 'xxx', // generated ethereal user
      pass: 'xxx' // generated ethereal password
    },
    tls: {
      rejectUnauthorized: false,
    },
  });

  // setup email data with unicode symbols
  let mailOptions = {
    from: `"website enquiry " <${email}>`, // sender address
    to: "admin@xxx.xx, enquiry@xxx.xx", // list of receivers
    subject: `${subject} ✔`, // Subject line
    text: `name: ${name}, \n email: ${email}, \n message: ${message}\n`, // plain text body
  };

  // send mail with defined transport object
  transporter.sendMail(mailOptions)
  .then(() => {
    callback(null, { statusCode: 200, body: 'Success' });
  })
  .catch(e => callback(e, { statusCode: 500, body: 'Error sending email' }));

};

主要问题

该表格记录在 Netlify 上的提交中。问题出在函数上:

正在开发中(使用 netlify-lambda 在本地托管 lambda 函数)我收到了网站上输入的属性。

在生产中,属性未定义。并且完整的事件对象不会在函数中记录到控制台。

答案在于生产与开发中的事件参数。

修复:

// How to get post parameters in production
exports.handler = function(event, context, callback) {
  const payload = JSON.parse(event.body).payload;
  const { name, email, subject, message } = payload;
}