node.jsemailgatsbypostmark

Only first email sending with booking form


I have a website with a 3 stage booking form. Each stage should send 2-3 emails via Postmark.

It seems to work in development but when pushed to Netlify only 1 email is sent on each stage as shown below (so total 3 processed & delivered instead of 7). postmark email activity

I'm not the best with Node.js so think I might be doing something wrong with the .then part?? Would appreciate any feedback/advice!

*note: First stage code shown below, although all have the same format. I know I could use postmarks batch send, but in stage 3 of form I use different templates so think I need separate client.sendEmailWithTemplate calls for that so have just used this method for all because of this + the low number of emails.

// Require:
var postmark = require("postmark");

// Send an email:
var client = new postmark.ServerClient(process.env.POSTMARK_AUTH);

//function to validate token with google re-captcha
async function validateHuman(token){
const secret = process.env.GATSBY_RECAPTCHA_SECRET;
const response = await fetch(`https://www.google.com/recaptcha/api/siteverify?secret=${secret}&response=${token}`,
  {
      method: "POST",
  } 
)
const data = await response.json();
return data.success;
}

//main function
export default async(req, res) => {
  res.setHeader('Access-Control-Allow-Origin', '*');
  console.log(req.body);
  //call re-captcha validation function
  const human = await validateHuman(req.body.token);
  if (!human){
      // console.log("this message shows we're getting to the !human part")
      res.status(400);
      res.json({errors: ["Please, you're not fooling us, bot."]})
      return;
  }
  try {
    let message = {
      "From": "*clientemail",
      "To": "*clientemail",
      "ReplyTo": "*clientemail",
      "TemplateId" : 36706722,
      "TemplateModel": {
        "name": req.body.name,
        "email": req.body.email,
        "phone": req.body.phone,
        "message": req.body.message
      },
      "MessageStream": "outbound"
    }
    //send emails if human
    client.sendEmailWithTemplate(message).then(
      () => {
        //I update email template here too in later form stage
        console.log("customer-support-sent")
        message.To = "daniel@thoughtfulhq.com"
        message.ReplyTo = req.body.email
        client.sendEmailWithTemplate(message)
      }
    ).then(
      () => {
        console.log("client-support-sent")
        // message.To = "daniel@thoughtfulhq.com"
        // console.log(message)
        // client.sendEmailWithTemplate(message)
      }
    ).then(
      () => {
        console.log("backup-support-sent")
        return res.status(200).json({
          message: "This is updated",
        })
      }
    )
  } catch (err) {
    console.log(err)
    return res.status(500).json({ message: "There was an error", error: err })
  }
}

Solution

  • Updated after new details:

    It's hard to tell for sure, but if you're getting errors, you're not likely to see them with that code. You're using try / catch inside your async function, but you're using .then style promises instead of await. Either use await + try + catch or use .then + .catch. try/catch only works for promises if you use await.

    export default async(req, res) => {
      res.setHeader('Access-Control-Allow-Origin', '*');
      console.log(req.body);
      //call re-captcha validation function
      const human = await validateHuman(req.body.token);
      if (!human){
          // console.log("this message shows we're getting to the !human part")
          res.status(400);
          res.json({errors: ["Please, you're not fooling us, bot."]})
          return;
      }
      try {
        let message = {
          "From": "*clientemail",
          "To": "*clientemail",
          "ReplyTo": "*clientemail",
          "TemplateId" : 36706722,
          "TemplateModel": {
            "name": req.body.name,
            "email": req.body.email,
            "phone": req.body.phone,
            "message": req.body.message
          },
          "MessageStream": "outbound"
        }
    
        //send emails if human
        await client.sendEmailWithTemplate(message)
        console.log("customer-support-sent")
    
        //I update email template here too in later form stage
        message.To = "daniel@thoughtfulhq.com"
        message.ReplyTo = req.body.email
        await client.sendEmailWithTemplate(message)
        console.log("client-support-sent")
    
        // message.To = "daniel@thoughtfulhq.com"
        // console.log(message)
        // await client.sendEmailWithTemplate(message)
        console.log("backup-support-sent")
    
        return res.status(200).json({
          message: "This is updated",
        })
      } catch (err) {
        console.log(err)
        return res.status(500).json({ message: "There was an error", error: err })
      }
    }
    

    Separately, if you want to stick with .then, use .catch. Also, you need to return the promise, or it's not going to work either:

      //send emails if human
      /**
       * =============== Added this return statement ===============
       * This one is technically optional, but it's a best practice to return
       * the promise chain if it's the last step of a method. That way, if you
       * ever wrap this function, you can handle the promise chain in the new parent.
       */
      return client.sendEmailWithTemplate(message).then(
        () => {
          //I update email template here too in later form stage
          console.log("customer-support-sent")
          message.To = "daniel@thoughtfulhq.com"
          message.ReplyTo = req.body.email
          /**
           * =============== Added this return statement ===============
           * If you don't return it, your promise chain will skip this promise, and
           * if sendEmailWithTemplate promise rejects, it will be "unhandled promise rejection"
           */
          return client.sendEmailWithTemplate(message)
        }
      ).then(
        () => {
          console.log("client-support-sent")
          // message.To = "daniel@thoughtfulhq.com"
          // console.log(message)
          /**
           * =============== Added this return statement ===============
           * If you don't return it, your promise chain will skip this promise, and
           * if sendEmailWithTemplate promise rejects, it will be "unhandled promise rejection"
           */
          // return client.sendEmailWithTemplate(message)
        }
      ).then(
        () => {
          console.log("backup-support-sent")
          return res.status(200).json({
            message: "This is updated",
          })
        }
      ).catch((err) => {
        console.log(err)
        return res.status(500).json({ message: "There was an error", error: err })
      })
    

    FWIW, I still recommend you drop the .then and just use await. You're already using await higher up in this method, and you should generally avoid mixing await & .then (this isn't always true, but it's a good rule to start with).


    [Original Response]

    Looking at your screenshot, your assumption appears to be incorrect, and the emails are "getting sent", and gmail isn't accepting it.

    According the Postmark Documentation, "Processed" means that you sent the email fine, but they're trying to hand it off to the recipient's email servers, and your email will either deliver or bounce, and there's nothing you can do to hurry it up. If it does bounce, you'll learn a lot more.

    From those docs:

    When a message is stuck as Processed, usually there is not much that can be done except waiting. That said, if you notice a sudden and significant increase in Processed messages for a specific email provider, do let our team know and we can investigate that further.


    It's also possible it's just a gmail problem. Try using https://www.mailinator.com to test it. They'll accept pretty much anything, so you can see if it's "a gmail problem" or "a you problem".