I created a transporter class to send emails:
export class MailTransporter {
receiver: string;
private transporter: Transporter;
constructor(receiver: string) {
this.receiver = receiver;
this.transporter = this.getTransporter();
}
private getTransporter() {
const { MAIL_USERNAME: user, MAIL_PASSWORD: pass, MAIL_HOST: host, MAIL_PORT: port } = process.env;
if (!user || !pass || !host || port) {
// NEXT LINE THROWS AN ERROR
throw new Error('Specify MAIL_USERNAME, MAIL_PASSWORD, MAIL_HOST and MAIL_PORT in .env');
}
const transporter = nodemailer.createTransport({
host,
port: Number(port),
secure: true,
auth: {
user,
pass,
},
});
return transporter;
}
public async sendMail(formValues: string) {
const values: FormValues = JSON.parse(formValues);
const message: SendMailOptions = {...};
await this.transporter.sendMail(message, (err, info) => {
if (err) {
throw err;
}
console.log('Email successfully sent. Info:\n', info);
});
}
}
And calling sendMail function from within handler function:
export default async function Handler(req: NextApiRequest, res: NextApiResponse) {
const { body } = req;
try {
const response = await MessageTransporter.sendMail(body); //MessageTransporter is an instance of MailTransporter
res.status(200).json({ success: true, message: 'OK' });
} catch (error) {
res.json({ success: false, message: 'Could not send the message' });
}
}
But the error thrown in MailTransporter isn't being catched in Handler, instead I'm getting the error in my console 
And in my browser I'm getting 500 error on my POST request.
Could you please explain what's going on there? Why the error isn't catched inside try catch of handler?
Also, I'm kinda new to js classes so if you have anything to say about class design, please do.
The call to getTransporter is inside the constructor of MailTransporter, so you should be checking it at the invocation site where the instance of MessageTransporter is getting created.