Mailgun not working on production but working on local

My site: youthful-wright-0e66fa.netlify.app
The function URL: /api/mailer-new-blog-post

Code

const Mailgun = require('mailgun-js');
const consts = require('./consts');

exports.handler = async (event) => {
  const authKey = event.headers.authorization;
  if (!authKey || authKey !== process.env.MAILGUN_WEBHOOK_AUTH_KEY) {
    console.log('failed auth');
    return {
      statusCode: 403,
      body: JSON.stringify({
        message: 'Unauthorized access.',
      }),
    };
  }

  const DOMAIN = consts.DOMAIN_NAME;
  const mailgun = Mailgun({ apiKey: process.env.MAILGUN_API, domain: DOMAIN });
  const { title, slug } = JSON.parse(event.body).data;
  const mailgunData = {
    from: 'Mailer <mailer@email.com>',
    to: 'listname@email.com',
    subject: `New Blog Post - ${title}`,
    template: 'new-blog-post-mailer-template',
    'h:X-Mailgun-Variables': JSON.stringify({
      title,
      slug,
    }),
    'h:Reply-To': 'email@email.com',
  };

  mailgun.messages().send(mailgunData, (error, body) => {
    console.log('send()');
    if (error !== undefined) {
      console.log(error);
      return {
        statusCode: 500,
        body: error,
      };
    }
    console.log(body.message);
    return {
      statusCode: 200,
      body: body.message,
    };
  });
  console.log('end');
  return {
    statusCode: 200,
  };
}

I used console.log() as marker. On local testing there’s no problem to see

end
send()
Queued. Thank you. # consolo.log(body.message);

But on production I can only see end in function log.

8:57:31 PM: 2021-03-10T07:57:31.860Z	bf3c0ab0-1616-4b63-b6fd-ba8f17990205	INFO	end
8:57:31 PM: Duration: 19.92 ms	Memory Usage: 88 MB	Init Duration: 378.35 ms

On production, I’ve debugged process.env to ensure MAILGUN_API and WEBHOOK_AUTH_KEY are valid. I also debugged mailgunData and there’s no problem too. So everything seems fine. Just it won’t send email on production.

I’ve spent like 2 hours lol. T_T Would you guys have some clue please?

UPDATE:
Maybe the function is terminated before Mailgun gets called?
Or there’s external access restrictions? I think it may call smtp.mailgun.org at some stage.

UPDATE2:
I found Mailgun ditched mailgun-js and suggests to migrate to the new lib mailgun.js (with a dot). So I did that and it behaves the same - working on build but not on live.

mailgun.messages.create(consts.DOMAIN_NAME, mailgunData)
    .then((body) => {
      console.log(body.message);
      response = body;
    })
    .catch((error) => {
      hasError = true;
      console.log(error);
      response = error;
    })
    .finally(() => {
      console.log(response);
      return {
        statusCode: hasError ? 500 : 200,
        body: response,
      };
    });

I can’t see any console.log in live function logs.

I’ll ask Maingun support as well for some clues.

FINAL UPDATE: SOLUTION

Ok I made it working… which is good but I don’t actually understand haha.

So I changed .then().catch() chain to try catch and await. It works on build and live. Hopefully it helps whoever facing similar issue.

  try {
    const response = await mailgun.messages.create(consts.DOMAIN_NAME, mailgunData);
    return {
      statusCode: 200,
      body: response.message,
    };
  } catch (e) {
    return {
      statusCode: 500,
      body: e,
    };
  }
2 Likes

@perry any explanation please? :grimacing: .then().catch() doesn’t work on Netlify Functions environment

Hey there,
Glad to hear that you figured it out! I don’t think this is a Netlify Functions issue as much as a JS/promises question, so it’s a bit out of scope for us to debug. Under the hood, functions are AWS Lambdas, which fully support promises. Maybe this post will be helpful to others who run into this (in addition to great snippet above): node.js - Strange behaviour when trying to send transactional emails using AWS Lambda and Mailgun - Stack Overflow

1 Like