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

У меня есть статический веб-сайт на 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-based и 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: "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) я получаю свойства, указанные на сайте.

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

1 Ответ

2 голосов
/ 01 апреля 2019

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

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

// 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;
}
...