1

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?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.