Mailgun - 401 forbidden

18.1k Views Asked by At

I try to send a email message by using mailgun. I use node.js (nest.js) and this is my mail service. What should I change? When I try to send first email (description in mailgun official website) I got the same error message.

import { Injectable } from '@nestjs/common';
import * as Mailgun from 'mailgun-js';
import { IMailGunData } from './interfaces/mail.interface';
import { ConfigService } from '../config/config.service';

@Injectable()
export class MailService {
  private mg: Mailgun.Mailgun;

  constructor(private readonly configService: ConfigService) {
    this.mg = Mailgun({
      apiKey: this.configService.get('MAILGUN_API_KEY'),
      domain: this.configService.get('MAILGUN_API_DOMAIN'),
    });
  }

  send(data: IMailGunData): Promise<Mailgun.messages.SendResponse> {
    console.log(data);
    console.log(this.mg);
    return new Promise((res, rej) => {
      this.mg.messages().send(data, function (error, body) {
        if (error) {
          console.log(error);
          rej(error);
        }
        res(body);
      });
    });
  }
}

When I try to send message I get 401 error with forbidden description.

My mg (console.log(this.mg))

Mailgun {
  username: 'api',
  apiKey: '920d6161ca860e7b84d9de75e14exxx-xxx-xxx',
  publicApiKey: undefined,
  domain: 'lokalne-dobrodziejstwa.pl',
  auth: 'api:920d6161ca860e7b84d9de75e14exxx-xxx-xxx',
  mute: false,
  timeout: undefined,
  host: 'api.mailgun.net',
  endpoint: '/v3',
  protocol: 'https:',
  port: 443,
  retry: 1,
  testMode: undefined,
  testModeLogger: undefined,
  options: {
    host: 'api.mailgun.net',
    endpoint: '/v3',
    protocol: 'https:',
    port: 443,
    auth: 'api:920d6161ca860e7b84d9de75e14exxx-xxx-xxx',
    proxy: undefined,
    timeout: undefined,
    retry: 1,
    testMode: undefined,
    testModeLogger: undefined
  },
  mailgunTokens: {}
}

My email body

{
  from: '[email protected]',
  to: '[email protected]',
  subject: 'Verify User',
  html: '\n' +
    '                <h3>Hello [email protected]!</h3>\n' +
    '            '
}
8

There are 8 best solutions below

0
user3765649 On

Try to send email to yourself (account email) via this command in console:

curl -s --user 'api:YOUR_API_KEY' \
    https://api.mailgun.net/v3/YOUR_DOMAIN_NAME/messages \
    -F from='Excited User <mailgun@YOUR_DOMAIN_NAME>' \
    -F to=YOU@YOUR_DOMAIN_NAME \
    -F [email protected] \
    -F subject='Hello' \
    -F text='Testing some Mailgun awesomeness!'

is it working?

If its not.. I assume you have written api and domain correctly so later if you have free acount you should check authorized recipant on overview section (you cant send email everywhere you want on trial account you have to type it first)

enter image description here If you didnt find solution this is how I have done my mailService (working) so you can just try it out i used nodemailer to do this:

import { Injectable, InternalServerErrorException, OnModuleInit } from '@nestjs/common';
import { readFileSync } from 'fs';
import { compile } from 'handlebars';
import { join } from 'path';
import * as nodemailer from 'nodemailer';
import { Options } from 'nodemailer/lib/mailer';
import * as mg from 'nodemailer-mailgun-transport';

import { IReplacement } from './replacements/replacement';
import { ResetPasswordReplacement } from './replacements/reset-password.replacement';

@Injectable()
export class MailService implements OnModuleInit {
  private transporter: nodemailer.Transporter;

  onModuleInit(): void {
    this.transporter = this.getMailConfig(); 
  }

  sendResetPasswordMail(email: string, firstName: string = '', lastName: string = ''): void { // this is just example method with template but you can use sendmail directly from sendMail method
    const resetPasswordReplacement = new ResetPasswordReplacement({
      firstName,
      lastName,
      email,
    });

    this.sendMail(
      proccess.env.MailBoxAddress),
      email,
      'Change password',
      this.createTemplate('reset-password', resetPasswordReplacement),
    );
  }

  sendMail(from: string, to: string, subject: string, body: string): void {
    const mailOptions: Options = { from, to, subject, html: body };

    return this.transporter.sendMail(mailOptions, (error) => {
      if (error) {
        throw new InternalServerErrorException('Error');
      }
    });
  }

  private getMailConfig(): any {
    return nodemailer.createTransport(mg({
      auth: {
        api_key: proccess.env.MailApiKey,
        domain: proccess.env.MailDomain
      },
    }));
  }

  private createTemplate(fileName: string, replacements: IReplacement): string {
    const templateFile = readFileSync(join(__dirname, 'templates', `${fileName}.html`), { encoding: 'utf-8' });
    const template = compile(templateFile);
    return template(replacements);
  }
}

and the

const templateFile = readFileSync(join(__dirname, 'templates', `${fileName}.html`), { encoding: 'utf-8' });

definates where html file with content is located so how it looks (in this case reset-password.html):

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Password reset</title>
</head>
<body>
  <div>Welcome {{firstName}} {{lastName}}</div>
</body>
</html>

and values in {{}} wil be replaced by library automatically

in this example example ResetPasswordReplacement its noly basic object which contains 3 properties and it inherits by IReplacement which is empty interface - made it only for define values in template file

sources:

  1. https://www.npmjs.com/package/nodemailer-mailgun-transport
  2. https://documentation.mailgun.com/en/latest/quickstart-sending.html#send-with-smtp-or-api
2
Ben On

I had this problem when my domain was in an EU zone. When you're using an EU zone, you have to specify it in the config - this isn't clearly explained by Mailgun.

So it would be something like this:

var mailgun = require("mailgun-js")({
  apiKey: API_KEY,
  domain: DOMAIN,
  url: 'https://api.eu.mailgun.net',
});
1
J. Diaz On

Another possible case that happened to me:
I initially installed mailgun-js with npm and started using yarn instead, then it returned 401 Forbidden in every request. So yarn add mailgun-js resolved it.

0
Lonare On

from mailgun api v3 onwards you have to:

var formData = require('form-data');
            const Mailgun = require('mailgun.js');
            const mailgun = new Mailgun(formData);
            const mg      = mailgun.client({
                username: 'api', 
                key: process.env.EMAIL_MAILGUN_API_KEY
            }); 
            
            mg.messages.create(process.env.EMAIL_MAILGUN_HOST, {
                from: "sender na,e <"+process.env.EMAIL_FROM+">",
                to: ["[email protected]"],
                subject: "Verify Your Email",
                text: "Testing some Mailgun awesomness!",
                html: "<h1>"+req+"</h1>"
              })
              .then(msg => {
                console.log(msg);
                res.send(msg);
              }) // logs response data
              .catch(err => { 
                console.log(err);
                res.send(err);
              }); // logs any error
1
anaveed On

To use mailgun API, whitelist your server IP from where you are want to send emails using mailgun web console.

Settings > Security & Users > API security > IP Whitelist

1
Joep On

EU USERS: For mailgun v3 you have to specify the eu endpoint in the url option in mailgun.client() like like this :

const API_KEY = "xxxxxxxxXxxxxxxxxxxxxxxxxxxx-xxxxxxx-xxxxxx";
const DOMAIN = "mydomaim.com";

const formData = require('form-data');
const Mailgun = require('mailgun.js');

const mailgun = new Mailgun(formData);
const client = mailgun.client({
  username: 'api',
  key: API_KEY,
  url:"https://api.eu.mailgun.net"
});
// console.log(client)

const messageData = {
  from: 'Yoopster <[email protected]>',
  to: '[email protected]',
  subject: 'Hello',
  text: 'Testing some Mailgun awesomeness!'
};

client.messages.create(DOMAIN, messageData)
  .then((res) => {
    console.log(res);
  })
  .catch((err) => {
    console.error(err);
  });
0
Allie Moosa On

If you are still looking for an answer using golang script Add the following lines

mg := mailgun.NewMailgun()

//When you have an EU-domain, you must specify the endpoint

mg.SetAPIBase("https://api.eu.mailgun.net/v3")
0
Ivan G. On

One other possibility is that you are using the wrong domain to configure the client. For example, even if you are sending from example.com, but you have configured your mailgun domain to be mg.example.com, you will want to pass mg.example.com when configuring the client