Firebase cloud function throws TypeError when using Mailgun for email sending

Hey everyone, I’m having trouble with my Firebase cloud function. I’m trying to send emails using Mailgun in a Flutter app. The weird thing is, the email actually gets sent, but then my app crashes because of an error. Here’s what’s going on:

const sendEmail = functions.https.onCall((data, context) => {
  console.log('Email request received');
  const emailContent = {
    from: 'Happy User <[email protected]>',
    to: '[email protected]',
    subject: 'Greetings',
    text: 'Just testing out this cool Mailgun feature!'
  };

  mailgunClient.messages().send(emailContent, (error, response) => {
    if (error) { console.log('Oops, error:', error); }
    console.log('Email sent:', response);
  })
    .catch((err) => { console.log('Caught an error:', err); });
});

The error I’m getting is:
TypeError: Cannot read property 'catch' of undefined

I’ve tried different function types (onRequest, onCall, trigger) and tinkered with returning promises or not, but nothing has fixed the issue. Any ideas on what might be going wrong? Thanks!

I’ve dealt with this exact issue in one of my projects. The root of the problem is that Mailgun’s send method doesn’t return a Promise, which is what Firebase expects for async operations.

Here’s a trick I found that works like a charm:

Instead of using the callback approach, you can use the Mailgun-js library’s promise interface. It’s much cleaner and plays nicely with Cloud Functions. Here’s how I refactored my code:

const sendEmail = functions.https.onCall(async (data, context) => {
  console.log('Email request received');
  const emailContent = {
    from: 'Happy User <[email protected]>',
    to: '[email protected]',
    subject: 'Greetings',
    text: 'Just testing out this cool Mailgun feature!'
  };

  try {
    const result = await mailgunClient.messages.create('YOUR_DOMAIN', emailContent);
    console.log('Email sent:', result);
    return { success: true, messageId: result.id };
  } catch (error) {
    console.error('Failed to send email:', error);
    throw new functions.https.HttpsError('internal', 'Failed to send email');
  }
});

This approach has worked flawlessly for me, and it should resolve your TypeError issue while keeping your code clean and easy to maintain.

ey mate, looks like ur missing a return statement. mailgunClient.messages().send() doesn’t return a promise, so u can’t chain .catch() to it. Try wrapping the send call in a Promise and return that. Somethin like:

return new Promise((resolve, reject) => {
mailgunClient.messages().send(emailContent, (error, response) => {
if (error) reject(error);
else resolve(response);
});
});

I’ve encountered a similar issue before. The problem lies in the asynchronous nature of the Mailgun send operation. Since it’s using a callback, the function completes before the email is sent, leading to the error you’re seeing.

To resolve this, you need to wrap the Mailgun operation in a Promise and return it. This ensures the function waits for the email to be sent before completing. Here’s how you can modify your code:

const sendEmail = functions.https.onCall((data, context) => {
  console.log('Email request received');
  const emailContent = {
    from: 'Happy User <[email protected]>',
    to: '[email protected]',
    subject: 'Greetings',
    text: 'Just testing out this cool Mailgun feature!'
  };

  return new Promise((resolve, reject) => {
    mailgunClient.messages().send(emailContent, (error, response) => {
      if (error) {
        console.log('Oops, error:', error);
        reject(error);
      } else {
        console.log('Email sent:', response);
        resolve(response);
      }
    });
  });
});

This modification should address the TypeError while ensuring that your Firebase Cloud Function waits for the email send operation to complete before terminating.