Nodemailer Sending Email hangs with a ETIMEDOUT and at Resolved but eventually sends email

So I have this one problem with an app I am building using Nodemailer to send email to an SMTP server (or gmail) and I am getting a weird problem.

TL;DR: The email does get sent but it’s rare. Other times it just hangs at Resolved then eventually times out (I added a time out).

Here is a video of what the console is doing: Here

As you can see in the video, eventually the email gets sent. Then it times out.

I get an ‘ETIMEDOUT’ error on most of the times it attempts to send.

Not that it’s needed but I’m sending an email by pushing a button on a site built with ReactJS. I also tried directly accessing the API function using Thunder Client. That has nothing to do with it.

Here is the transporter:
`// Define which service to use
// gmail = Use gmail’s service (must have GmailSMTPUser and GmailSMTPAppPass setup)
// ll = Use LumiereLabs’s service
const emailService = serviceSettings.use
// Configure the transporter

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>switch (emailService) {
case "gmail":
return nodemailer.createTransport({
service: 'gmail',
auth: {
user: serviceSettings.services.gmail.user,
pass: serviceSettings.services.gmail.pass
},
logger: true,
debug: true,
maxConnections: 5, // Maximum number of connections to keep in the pool
maxMessages: 100, // Maximum number of messages to send per connection
rateLimit: 10, // Maximum number of messages to send per second
pool: true, // disable connection pooling
connectionTimeout: 10000, // 10 seconds
socketTimeout: 10000, // 10 seconds
greetingTimeout: 5000 // 5 seconds
})
break
case "ll":
return nodemailer.createTransport({
host: 'smtp.lumierelabs.org',
port: 587,
secure: false, // true for 465, false for others
requireTLS: true,
auth: {
user: serviceSettings.services.ll.user,
pass: serviceSettings.services.ll.pass
},
tls: {
rejectUnauthorized: false // if using self-signed certificates
},
logger: true,
debug: true,
maxConnections: 5, // Maximum number of connections to keep in the pool
maxMessages: 100, // Maximum number of messages to send per connection
rateLimit: 10, // Maximum number of messages to send per second
pool: true, // disable connection pooling
connectionTimeout: 10000, // 10 seconds
socketTimeout: 10000, // 10 seconds
greetingTimeout: 5000 // 5 seconds
})
break
}`
</code>
<code>switch (emailService) { case "gmail": return nodemailer.createTransport({ service: 'gmail', auth: { user: serviceSettings.services.gmail.user, pass: serviceSettings.services.gmail.pass }, logger: true, debug: true, maxConnections: 5, // Maximum number of connections to keep in the pool maxMessages: 100, // Maximum number of messages to send per connection rateLimit: 10, // Maximum number of messages to send per second pool: true, // disable connection pooling connectionTimeout: 10000, // 10 seconds socketTimeout: 10000, // 10 seconds greetingTimeout: 5000 // 5 seconds }) break case "ll": return nodemailer.createTransport({ host: 'smtp.lumierelabs.org', port: 587, secure: false, // true for 465, false for others requireTLS: true, auth: { user: serviceSettings.services.ll.user, pass: serviceSettings.services.ll.pass }, tls: { rejectUnauthorized: false // if using self-signed certificates }, logger: true, debug: true, maxConnections: 5, // Maximum number of connections to keep in the pool maxMessages: 100, // Maximum number of messages to send per connection rateLimit: 10, // Maximum number of messages to send per second pool: true, // disable connection pooling connectionTimeout: 10000, // 10 seconds socketTimeout: 10000, // 10 seconds greetingTimeout: 5000 // 5 seconds }) break }` </code>
switch (emailService) {
    case "gmail":
        return nodemailer.createTransport({
            service: 'gmail',
            auth: {
                user: serviceSettings.services.gmail.user,
                pass: serviceSettings.services.gmail.pass
            },
            logger: true,
            debug: true,
            maxConnections: 5, // Maximum number of connections to keep in the pool
            maxMessages: 100, // Maximum number of messages to send per connection
            rateLimit: 10, // Maximum number of messages to send per second
            pool: true, // disable connection pooling
            connectionTimeout: 10000,  // 10 seconds
            socketTimeout: 10000,      // 10 seconds
            greetingTimeout: 5000      // 5 seconds    
        })
    break

    case "ll":
        return nodemailer.createTransport({                    
            host: 'smtp.lumierelabs.org',
            port: 587,
            secure: false,       // true for 465, false for others
            requireTLS: true,
            auth: {
                user: serviceSettings.services.ll.user,
                pass: serviceSettings.services.ll.pass
            },
            tls: {
                rejectUnauthorized: false // if using self-signed certificates
            },
            logger: true,
            debug: true,
            maxConnections: 5, // Maximum number of connections to keep in the pool
            maxMessages: 100, // Maximum number of messages to send per connection
            rateLimit: 10, // Maximum number of messages to send per second
            pool: true, // disable connection pooling
            connectionTimeout: 10000,  // 10 seconds
            socketTimeout: 10000,      // 10 seconds
            greetingTimeout: 5000      // 5 seconds                
        })
    break
}`

Here is the function I created to handle the email:
`const sendEmail = async (mailOptions, successMessage, res, serviceSettings) => {
let toasts = []

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<code>const transporter = createTransporter(serviceSettings)
try {
let info = await transporter.sendMail(mailOptions)
// Send to notification
toasts.push({ message: successMessage, object: { sentEmail: true }, type: 'success' })
// Send to console
console.log('Email sent: ' + info.response)
} catch (error) {
// Send to notification
toasts.push({ message: `Error sending mail: ${error}`, object: { sentEmail: false }, type: 'error'})
// Send to console
console.error('Error sending email: ', error)
// Rethrow error to handle it upstream
throw error
} finally {
transporter.close() // close the connection pool
// return something
if(toasts.length > 0) {
// Toasts found!
// Check for type
if (toasts[0].type === "error") {
// Error
if (!res.headersSent) {
return res.status(400).json(toasts)
} else {
console.warn('Attempted to send a response after headers were already sent.');
}
} if (toasts[0].type === "unauthorized") {
// Unauthorized
if (!res.headersSent) {
return res.status(401).json(toasts)
} else {
console.warn('Attempted to send a response after headers were already sent.');
}
} else {
if (!res.headersSent) {
return res.status(200).json(toasts)
} else {
console.warn('Attempted to send a response after headers were already sent.');
}
}
}
}
</code>
<code>const transporter = createTransporter(serviceSettings) try { let info = await transporter.sendMail(mailOptions) // Send to notification toasts.push({ message: successMessage, object: { sentEmail: true }, type: 'success' }) // Send to console console.log('Email sent: ' + info.response) } catch (error) { // Send to notification toasts.push({ message: `Error sending mail: ${error}`, object: { sentEmail: false }, type: 'error'}) // Send to console console.error('Error sending email: ', error) // Rethrow error to handle it upstream throw error } finally { transporter.close() // close the connection pool // return something if(toasts.length > 0) { // Toasts found! // Check for type if (toasts[0].type === "error") { // Error if (!res.headersSent) { return res.status(400).json(toasts) } else { console.warn('Attempted to send a response after headers were already sent.'); } } if (toasts[0].type === "unauthorized") { // Unauthorized if (!res.headersSent) { return res.status(401).json(toasts) } else { console.warn('Attempted to send a response after headers were already sent.'); } } else { if (!res.headersSent) { return res.status(200).json(toasts) } else { console.warn('Attempted to send a response after headers were already sent.'); } } } } </code>
const transporter = createTransporter(serviceSettings)
            
try {
    let info = await transporter.sendMail(mailOptions)

    // Send to notification
    toasts.push({ message: successMessage, object: { sentEmail: true }, type: 'success' })

    // Send to console
    console.log('Email sent: ' + info.response)
} catch (error) {
    // Send to notification
    toasts.push({ message: `Error sending mail: ${error}`, object: { sentEmail: false },  type: 'error'})

    // Send to console
    console.error('Error sending email: ', error)

    // Rethrow error to handle it upstream
    throw error
} finally {
    transporter.close() // close the connection pool

    // return something
    if(toasts.length > 0) {
        // Toasts found!
        // Check for type
        if (toasts[0].type === "error") {                                               
            // Error                                                                        
            if (!res.headersSent) {
                return res.status(400).json(toasts)
            } else {
                console.warn('Attempted to send a response after headers were already sent.');
            }                      
        } if (toasts[0].type === "unauthorized") {
            // Unauthorized
            if (!res.headersSent) {
                return res.status(401).json(toasts)
            } else {
                console.warn('Attempted to send a response after headers were already sent.');
            }                      
        } else {
            if (!res.headersSent) {
                return res.status(200).json(toasts)
            } else {
                console.warn('Attempted to send a response after headers were already sent.');
            }                      
        }
    }
}

}`

The function is called from a userController.js on a express JS backend:
await sendEmail(mailOptions, successMessage, res, serviceSettings)

Node Version: 22.2.0
NPM Version: 10.7.0
Development Operating System: Windows 11
SMTP Server OS: Ubuntu 22.04 using Postfix and Dovecot

Any help would be greatly appreciated.

What have I done to mitigate this?

  1. Changed from a self-hosted SMTP server (smtp.lumierelabs.org) to a gmail service. Same result. So it’s not an SMTP problem.

  2. Created a separate app aside from the project that has the nodemailer and still got the result.

  3. Restarted computer. Same result.

  4. Checked telnet of smtp.lumierelabs.org on Command Prompt, smtp server works. So I know it’s not an SMTP problem.

  5. Re-installed nodemailer

  6. Googled the problem and can’t find something similiar.

  7. Turned off Windows Defender Firewall, no change.

New contributor

FinuxFirit is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật