Postmark API on ExpressJS Endpoint / ERR_HTTP_HEADERS_SENT

Viewed 23

I am still a beginner level programmer and also completely self taught keep that in mind while answering to my post.

I have a ExpressJS server running with an endpoint to send email via postmarkAPI. There are Errors happening some of them are critical and cause server to crash.

I need to answer all requests seamlessly to my frontend since otherwise it would timeout, crash etc.

Here is the error I get:

[39m node:internal/errors:477 [39m ErrorCaptureStackTrace(err); [39m Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client [39m at new NodeError (node:internal/errors:387:5) [39m at ServerResponse.setHeader (node:_http_outgoing:603:11) [39m at ServerResponse.header (/app/node_modules/express/lib/response.js:771:10) [39m at ServerResponse.send (/app/node_modules/express/lib/response.js:170:12) [39m at ServerResponse.json (/app/node_modules/express/lib/response.js:267:15) [39m at ServerResponse.send (/app/node_modules/express/lib/response.js:158:21) [39m at /app/app.js:333:21 [39m at runMicrotasks () [39m at processTicksAndRejections {code: 'ERR_HTTP_HEADERS_SENT'}

I understand that I am sending multiple answers somehow. I think that in some cases then() and catch() are both triggered and therefore I am sending two responds. But I don't know how to fix this.

Here is the Code:

app.post("/mail", (req, res) => {
  const authHeader = req.headers.authorization;
  //console.log(req.body);
  if (authHeader.split(" ")[1] === process.env.TOKEN) {
    const from = req.body.mail.from;
    const to = req.body.mail.to;
    const cc = req.body.mail.cc;
    const bcc = req.body.mail.bcc;
    const subject = req.body.mail.subject;
    const htmlBody = req.body.mail.htmlBody;
    const textBody = req.body.mail.textBody;
    const replyTo = req.body.mail.replyTo;
    const files = req.body.mail.files;
    const tag = req.body.mail.tag;
    if (files.length > 0) {
      let attachments = [];
      let promises = [];
      for (i in files) {
        console.log(i);
        let fileName = files[i].name;
        let shareLink = files[i].url;
        promises.push(
          axios
            .get(shareLink, {
              responseType: "arraybuffer",
            })
            .catch((err) => {
              console.log(err);
            })
            .then((response) => {
              console.log("Downloading & encoding files - Status Code: ", response.status);
              console.log(`typeof response.data: ${typeof response.data}`);
              const encoded = new Buffer.from(response.data).toString("base64");
              attachments.push({
                Name: fileName,
                Content: encoded,
                ContentType: "application/octet-stream",
              });
            })
        );
      }
      Promise.all(promises)
        .then(() => {
          sendEmail(
            from,
            to,
            cc,
            bcc,
            subject,
            htmlBody,
            textBody,
            replyTo,
            attachments,
            tag
          )
            .catch((err) => {
              console.log(err)
              res.send({
                error: err,
              });
            })
            .then((response) => {
              if (typeof response !== "undefined") {
                console.log(`typeof response: ${typeof response}`)
                if (typeof response.data !== "undefined") {
                  res.send({
                    status: 200,
                    response: response.data,
                  });
                }
              } else {
                res.send({
                  status: 500,
                  response:
                    "some error occured in postmark API connection - admin view serverlogs",
                });
              }
            });
        })
        .catch((err) => {
          console.log(err);
        });
    } else if (files.length < 1) {
      var attachments = [];
      sendEmail(
        from,
        to,
        cc,
        bcc,
        subject,
        htmlBody,
        textBody,
        replyTo,
        attachments,
        tag
      )
        .catch((err) => {
          res.send({
            error: err.message,
          });
        })
        .then((response) => {
          if (typeof response.data !== "undefined") {
            res.send({
              status: 200,
              response: response.data,
            });
          } else {
            res.send({
              status: 500,
              response:
                "some error occured in postmark API connection - admin view serverlogs",
            });
          }
        });
    }
  } else {
    res.sendStatus(403);
  }
});
//==========================================
//    FUNCTIONS
//==========================================
async function sendEmail(
  from,
  to,
  cc,
  bcc,
  subject,
  htmlBody,
  textBody,
  replyTo,
  attachments,
  tag
) {
  var config = {
    method: "post",
    url: "https://api.postmarkapp.com/email",
    headers: {
      "Content-Type": "application/json",
      Accept: "application/json",
      "X-Postmark-Server-Token": process.env.POSTMARK_KEY,
    },
    data: {
      From: from,
      To: to,
      Cc: cc,
      Bcc: bcc,
      Subject: subject,
      Tag: tag,
      HtmlBody: htmlBody,
      TextBody: textBody,
      ReplyTo: replyTo,
      Attachments: attachments,
    },
  };
  const promSendMail = axios(config);
  const resMailSent = await promSendMail;
  return resMailSent;
}

Any answer and advice that helps me fix this bug or improve my skills or code quality is welcome. Thanks in Advance

0 Answers
Related