使用 Netlify lambda 函数从 GatsbyJS 站点发送电子邮件

Using Netlify lambda functions to send emails from a GatsbyJS site

我正在学习本教程 https://dev.to/char_bone/using-netlify-lambda-functions-to-send-emails-from-a-gatsbyjs-site-3pnb I have everything set up but I get the following error in my terminal. I am able to get the hello world app working for the lambda function from here https://www.gatsbyjs.org/blog/2018-12-17-turning-the-static-dynamic/,这是开始第一个教程的先决条件。

RangeError [ERR_HTTP_INVALID_STATUS_CODE]: Invalid status code: undefined

这是带有表格的代码。你还可以在下面看到整个 repo。

import React from 'react'
import { HelmetDatoCms } from 'gatsby-source-datocms'
import { graphql } from 'gatsby'
import Layout from "../components/layout"

export default ({ data }) => {

  const [formState, setFormState] = React.useState({
    name: "",
    email: "",
    subject: "",
    message: "",
  })

  const onChange = (e) => {
    setFormState({...formState, [e.target.name]: e.target.value });
 }

 const submitForm = async (e) => {
  e.preventDefault();

  console.log("test");

  try{
    const response = await fetch("/.netlify/functions/sendmail", {
      method: "POST",
      body: JSON.stringify(formState),
    })

    if (!response.ok) {
      console.log(response);
      return
    }

    console.log("success email");

  } catch(e){

    console.log("error");

  }
}

  return(

  <Layout>

    <article className="sheet">
      <HelmetDatoCms seo={data.datoCmsPricing.seoMetaTags} />

        <section className="left-package-details">

          tests

        <div className="App">
      <form onSubmit={submitForm}>
        <label>
          Name
          <input
            type="text"
            name="name"
            value={formState.name}
            onChange={onChange}
          />
        </label>
        <label>
          Email
          <input
            type="email"
            name="email"
            value={formState.email}
            onChange={onChange}
          />
        </label>
        <label>
          Subject
          <input
            type="textarea"
            name="subject"
            value={formState.subject}
            onChange={onChange}
          />
        </label>
        <label>
          message
          <input
            type="text"
            name="message"
            value={formState.message}
            onChange={onChange}
          />
        </label>
        <button type="submit">Submit</button>
      </form>
    </div>


  )
}

更新

现在根据 Pierre 的回答,我收到了 500 错误

Request from ::ffff:127.0.0.1: POST /sendmail 
Response with status 500 in 3 ms.

我想知道它是否与它有关 POST' 来自本地主机,至少我知道现在是 sendgrid 给我错误。

我查看了 npm 调试部分,看到了这段代码,不确定具体放在哪里?

const {
  classes: {
    Mail,
  },
} = require('@sendgrid/helpers');
const mail = Mail.create(data);
const body = mail.toJSON();
console.log(body);

控制台错误

Response {type: "basic", url: "http://localhost:8000/.netlify/functions/sendmail", redirected: false, status: 500, ok: false, …}
type: "basic"
url: "http://localhost:8000/.netlify/functions/sendmail"
redirected: false
status: 500
ok: false
statusText: "Internal Server Error"
headers: Headers {}
body: (...)
bodyUsed: false
__proto__: Response

第二次更新

我现在在终端中收到以下错误实际上我认为我什至不需要 cc,我认为这是在说我没有价值,所以也许我的 env varaiable SENDGRID_TO_EMAIL没有通过?

Provide at least one of to, cc or bcc 

现在如果我像这样添加抄送

const msg = {
        to: SENDGRID_TO_EMAIL,
        cc:"email@email.com",
        from: email,
        subject: subject ? subject : 'Contact Form Submission',
        html: body,
    };

然后我收到 Unauthorized 消息

对于我的环境变量,我的根目录下有一个 .env 文件,其中包含以下内容

SENDGRID_API_KEY=SG.longsting
SENDGRID_TO_EMAIL=myemail@email.com

这是应该获取环境变量的行

const { SENDGRID_API_KEY, SENDGRID_TO_EMAIL } = process.env

查看 your source code,我很确定 sendgrid send 函数引发异常,并且您没有正确处理它:

try{
    await sgMail.send(msg)

    return {
        statusCode: 200,
        body: "Message sent"
    }
} catch(e){
    return {
        statusCode: e.code, // e.code is probably undefined
        body: e.message
    }
}

我快速查看了 sendgrid SDK,但没有发现任何提示它会抛出错误的 code 属性 对应于有效的 http 状态代码。

结果是您 return 以 undefined 作为状态代码的响应,因此 ERR_HTTP_INVALID_STATUS_CODE 错误。

尝试用以下内容替换您的 catch 块,您至少应该得到正确的响应,希望是来自 sendgrid SDK 的有用错误消息:

try {
    // same as before
} catch(e){
    return {
        statusCode: 500,
        body: e.message
    }
}

更新

您的问题可能与您的环境变量有关。您应该确保 SENDGRID_API_KEYSENDGRID_TO_EMAIL 设置正确。

对于你的开发环境,我认为你需要在你的函数文件中添加require('dotenv').config()

对于您的生产环境 (Netlify),您应该在 UI 中设置变量:https://docs.netlify.com/configure-builds/environment-variables/#declare-variables

最近我遇到了类似的问题,下面附上我对你的问题的解决方案。

文件夹结构 - 一块

Project
 |
 +-- public   
 +-- src
 |  |  
 |  +-- functions
 |      |
 |      +-- sendmail.js
 |
 |  +-- components
 |      |
 |      +-- ContactForm.js
 |

根目录中的 Lambda 函数文件夹

const sgMail = require("@sendgrid/mail")
const { SENDGRID_API_KEY, SENDGRID_TO_EMAIL } = process.env

exports.handler = async (event, context, callback) => {
  const payload = JSON.parse(event.body)
  const { email, message, name } = payload

  sgMail.setApiKey(SENDGRID_API_KEY)

  const msg = {
    to: SENDGRID_TO_EMAIL,
    from: email,
    subject: `New message from ${name}`,
    text: message,
  }

  try {
    await sgMail.send(msg)
    return {
      statusCode: 200,
      body: "Message sent",
    }
  } catch (err) {
    return {
      statusCode: err.code,
      body: err.message,
    }
  }
}

联系表格 - 一张

const formik = useFormik({
    initialValues: { name: "", email: "", message: "" },
    validationSchema,
    onSubmit: (values, { resetForm, setSubmitting }) => {
      axios
        .post("/.netlify/functions/sendmail", values)
        .then(res => {
          console.log(res)
          setSubmitting(false)
          resetForm({})
        })
        .catch(err => {
          console.log(err)
          setSubmitting(false)
        })
    },
  })

package.json - lambda 函数所需的包

"dependencies": {
    "@sendgrid/mail": "^6.5.5",
    "axios": "^0.19.2",
},
"devDependencies": {
    "http-proxy-middleware": "^1.0.3",
    "netlify-lambda": "^1.6.3",
    "npm-run-all": "^4.1.5",
},
"scripts": {
    "develop": "gatsby develop",
    "start": "run-p start:**",
    "start:app": "npm run develop",
    "start:lambda": "netlify-lambda serve src/functions",
    "build": "gatsby build && netlify-lambda build src/functions",
    "build:app": "gatsby build",
    "build:lambda": "netlify-lambda build src/functions"
 }

netlify.toml

[build]
  command = "npm run build"
  functions = "functions"
  publish = "public"

盖茨比-config.js

module.exports = {
  // other setup

  developMiddleware: app => {
    app.use(
      "/.netlify/functions/",
      proxy({
        target: "http://localhost:9000",
        pathRewrite: {
          "/.netlify/functions/": "",
        },
      })
    )
  },
}

在 Netlify 上设置适当的 env 变量,你应该可以开始了。希望它对某人有所帮助。