I'm encountering an error (ESOCKET - connect) while trying to send an email verification OTP using Nodemailer in my NestJS application. I'm using Gmail's SMTP server for email delivery. Here's a breakdown of my setup:
Mailer Configuration (app.module)
MailerModule.forRootAsync({
useFactory: (configService: ConfigService) => configService.get('mailer'),
inject: [ConfigService],
}),
mailer.config
export default () => ({
mailer: {
transport: {
host: process.env.MAIL_HOST,
port: parseInt(process.env.MAIL_PORT),
auth: {
user: process.env.MAIL_USER,
pass: process.env.MAIL_PASSWORD,
},
},
defaults: {
from: process.env.MAIL_FROM,
},
},
});
register-email.provider
import { ConflictException, Injectable } from '@nestjs/common';
import { FindOneByEmailProvider } from 'src/users/providers/find-one-by-email.provider';
// import { v4 as uuidv4 } from 'uuid';
import { MailerService } from '@nestjs-modules/mailer';
import { OtpProvider } from './otp.provider';
import { EmailDto } from '../dto/email.dto';
@Injectable()
export class RegisterEmailProvider {
constructor(
private readonly findOneByEmailProvider: FindOneByEmailProvider,
private readonly otpProvider: OtpProvider,
private readonly mailerService: MailerService,
) {
// Set up a periodic task to clean up expired OTPs
setInterval(() => this.otpProvider.cleanUpExpiredOtps(), 60 * 1000); // Run every minute
}
public async registerEmail(registerEmailDto: EmailDto) {
const { email } = registerEmailDto;
const existingUser = await this.findOneByEmailProvider.findOneByEmailProvider(email);
if (existingUser && existingUser.isActive === true) {
throw new ConflictException('Email already exists', {
description: 'Email already exists',
// cause: 'User already exists',
});
}
// const otp = uuidv4().slice(0, 6); // Generate a 6-character OTP
const otp = Math.floor(100000 + Math.random() * 900000).toString(); //numeric otp
const expiresAt = Date.now() + 15 * 60 * 1000; // Set expiration time to 15 minutes from now
this.otpProvider.setOtp(email, otp, expiresAt);
console.log('OTP:', otp);
// Send OTP via email
try {
await this.mailerService.sendMail({
to: email,
subject: 'Email Verification OTP',
text: `Your OTP for email verification is: ${otp}`,
});
console.log('OTP sent to email');
return { message: 'OTP sent to email' };
} catch (error) {
throw new ConflictException(error, 'Failed to send OTP email');
}
}
}
Error Message
{
"errno": -4039,
"code": "ESOCKET",
"syscall": "connect",
"address": "209.85.202.108",
"port": 587,
"command": "CONN"
}
Question
I'm getting this ESOCKET error when the register-email endpoint is hit. I've verified that my environment variables are set as follows:
# mailer configuration
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USER=my_email_account
MAIL_PASSWORD='xxxx xxxx xxxx xxxx' # my gmail application password
MAIL_FROM='"Sender" <[email protected]>'
What could be causing this issue, and how can I resolve it?