繁体   English   中英

Sendgrid NodeJS 收到之前已发送的邮件

[英]Sendgrid NodeJS recieved previous mail already sent

使用:NextJS, Firebase (Auth, DB, etc...), Hosted on Vercel, OVH Domains, (使用 next for 后端 (node))

基本上,我用 Sendgrid 库或 API v3 直接发送 email,我的邮件出现了奇怪的行为。

当我向任何地址发送邮件时,我根本没有收到邮件,我需要多次发出相同的请求才能得到第一个的答复,这不是很奇怪吗?

就像我向“joe@example.com”发送“1”一样,joe 什么也没收到,我用“2”发出相同的请求,joe 什么也没收到,然后我又发出一个“3”,最后 joe 收到了第一封邮件。

然后当我发送其他邮件时,我发送“4”我会收到“2”,等等......我觉得我的邮件中有一个队列。 起初,如果我没记错的话,当我使用下面的库时,邮件总是间隔 1。 然后我直接认为这是一个库问题,转到了 API。

使用图书馆

import { getAuth } from 'firebase-admin/auth'
import { supportConfig, websiteConfig, sendgridConfig } from 'src/config'
import sgMail from '@sendgrid/mail'
import path from 'path'
import fs from 'fs'

/**
 * @name verifyEmail
 * @description Send email verify link to user email
 * @param {string} email
 * @param {any} actionCodeSettings
 * @returns Promise<Void>
 */

export default async function verifyEmail(
  email: string,
  actionCodeSettings: any
): Promise<void> {
  const pathTemplate = path.join(
    process.cwd(),
    'src/api/lib/user/actionCode/emailTemplate/verifyEmail.html'
  )
  return await getAuth()
    .generateEmailVerificationLink(email as string)
    .then(async (link) => {
      sgMail.setApiKey(sendgridConfig.apiKey as string)
      fs.readFile(pathTemplate, 'utf8', async function (err, data) {
        if (err) {
          console.log(err)
          throw err
        }
        const msg = {
          to: [email, supportConfig.email as string],
          from: supportConfig.email as string,
          subject: "Email verification",
          text: 'Please click on the link',
          html: data.replace('{{link}}', link),
        }
        await sgMail
        .send(msg)
        .then(() => {
          console.log('Email sent!')
        })
        .catch((error) => {
          console.log(error)
          throw error
        })
      })
    })
    .catch((error) => {
      console.log(error)
      throw error
    })
}

直接使用 api

        const message = {
          personalizations: [
            {
              to: [
                {
                  email: email,
                },
              ],
            },
          ],
          from: {
            email: 'support@nerap.fr',
            name: 'Support',
          },
          replyTo: {
            email: 'support@nerap.fr',
            name: 'Support',
          },
          subject: 'Email verification',
          content: [
            {
              type: 'text/html',
              value: data.replace('{{link}}', link),
            },
          ],
        }
        await axios({
          method: 'post',
          url: 'https://api.sendgrid.com/v3/mail/send',
          headers: {
            Authorization: `Bearer ${sendgridConfig.apiKey}`,
            'Content-Type': 'application/json',
          },
          data: message,
        })

没什么特别的,就像 Sendgrid 给我们的模板。 老实说,我迷路了,我没有任何线索可以解决它。

疯狂的部分来了,它在本地完美运行。

所以我想我的结论是这样的。 Vercel 托管可能会受到 Sengrid 的限制或限制,这是唯一合理的方式。 就像,我不知道,我接受了定价版本,认为这是强迫人们使用付费版本的伎俩。 我愿意接受任何建议谢谢!

感谢您分享代码,它突出显示了一段异步代码,它允许您的 function 在运行之前完成。 在像 Vercel 这样的平台上,当 function 完成时,事件循环实际上被暂停,但在 function 再次运行时继续。 在这种情况下,您的代码在 function 结束之前没有完成,这就是为什么后来的电子邮件会触发 email 被发送。

转义的异步代码是在fs.readFile中使用 fs.readFile。 调用fs.readFile开始了从文件系统异步读取 email 模板的工作,并在完成时调用回调,然后发送 email。 但是,function 的执行将在完成之前继续并完成。 由于您对此代码中的所有其他内容都使用了 Promise,因此我建议您使用fs/promises (使用import { promises as fs } from 'fs'行),以便您可以像对待代码的fs.readFile一样对待 fs.readFile。 我使用 promise 版本在下面重写了您的 function,希望这能奏效。

import { getAuth } from 'firebase-admin/auth'
import { supportConfig, websiteConfig, sendgridConfig } from 'src/config'
import sgMail from '@sendgrid/mail'
import path from 'path'
import { promises as fs } from 'fs'

/**
 * @name verifyEmail
 * @description Send email verify link to user email
 * @param {string} email
 * @param {any} actionCodeSettings
 * @returns Promise<Void>
 */

export default async function verifyEmail(
  email: string,
  actionCodeSettings: any
): Promise<void> {
  const pathTemplate = path.join(
    process.cwd(),
    'src/api/lib/user/actionCode/emailTemplate/verifyEmail.html'
  )
  return await getAuth()
    .generateEmailVerificationLink(email as string)
    .then(async (link) => {
      sgMail.setApiKey(sendgridConfig.apiKey as string)
      try {
        const data = await fs.readFile(pathTemplate, 'utf8');
        const msg = {
          to: [email, supportConfig.email as string],
          from: supportConfig.email as string,
          subject: "Email verification",
          text: 'Please click on the link',
          html: data.replace('{{link}}', link),
        }
        await sgMail
        .send(msg)
        .then(() => {
          console.log('Email sent!')
        })
        .catch((error) => {
          console.log(error)
          throw error
        })
      } catch(error) {
        console.log(error)
        throw error
      }
      })
    .catch((error) => {
      console.log(error)
      throw error
    })
}

您的代码中确实存在混淆的then/catchasync/await组合。 我建议只使用一种样式来简化事情。 只需async/await ,您的代码可能如下所示:

import { getAuth } from 'firebase-admin/auth'
import { supportConfig, websiteConfig, sendgridConfig } from 'src/config'
import sgMail from '@sendgrid/mail'
import path from 'path'
import { promises as fs } from 'fs'

/**
 * @name verifyEmail
 * @description Send email verify link to user email
 * @param {string} email
 * @param {any} actionCodeSettings
 * @returns Promise<Void>
 */

export default async function verifyEmail(
  email: string,
  actionCodeSettings: any
): Promise<void> {
  const pathTemplate = path.join(
    process.cwd(),
    'src/api/lib/user/actionCode/emailTemplate/verifyEmail.html'
  )
  try {
    const auth = getAuth()
    const link = await auth.generateEmailVerificationLink(email as string)
    sgMail.setApiKey(sendgridConfig.apiKey as string)
    const data = await fs.readFile(pathTemplate, 'utf8')
    const msg = {
      to: [email, supportConfig.email as string],
      from: supportConfig.email as string,
      subject: "Email verification",
      text: 'Please click on the link',
      html: data.replace('{{link}}', link),
    }
    await sgMail.send(msg)
    console.log('Email sent!')
  } catch(error) {
    console.log(error)
    throw error
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM