Как подключить nodemailer к приложению Vue.js и Netlify с помощью лямбда-функций

У меня есть статический веб-сайт на Netlify, созданный с помощью Vue.js, и у меня есть особая потребность в захвате x-www-form-urlencoded данных, отправляемых по контактному маршруту.

Поскольку это спа и динамически отображаемая форма, я добавил это как в 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. 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, когда запускается prebuid, он удаляет текущую сборку функций и воссоздает ее, а затем заархивирует функции в каталог с зависимостями.

Вот 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: "[email protected], [email protected]", // 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) я получаю свойства, указанные на сайте.

В производстве свойства не определены. И полный объект события не регистрируется в консоли в функциях.


person Eckhardt    schedule 31.03.2019    source источник


Ответы (1)


Ответ кроется в параметрах события в производстве и в разработке.

исправление:

// 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;
}
person Eckhardt    schedule 01.04.2019