Skip to content

fix(email): respect hosts file for SMTP connections#3082

Open
0xSysR3ll wants to merge 1 commit into
developfrom
0xsysr3ll/fix/nodemailer-docker-hosts-resolution
Open

fix(email): respect hosts file for SMTP connections#3082
0xSysR3ll wants to merge 1 commit into
developfrom
0xsysr3ll/fix/nodemailer-docker-hosts-resolution

Conversation

@0xSysR3ll
Copy link
Copy Markdown
Contributor

@0xSysR3ll 0xSysR3ll commented May 27, 2026

Description

This PR fixes an issue where SMTP hostnames defined through Docker extra_hosts or /etc/hosts were not respected when sending email notifications.

Previously, nodemailer could resolve the SMTP hostname through DNS before opening the connection, which could bypass /etc/hosts.

How Has This Been Tested?

Tested locally with Docker:

  1. Built a seerr docker image from latest develop commit
  2. Started a maildev server
  3. Ran seerr with:
    --add-host example.com:host-gateway
  4. Verified that getent hosts example.com inside the container resolved to the host gateway.
  5. Confirmed the develop image did not reach the maildev server. In fact the container's
    /etc/hosts entry mapped example.com to the host gateway, but the SMTP
    client still followed nodemailer's DNS resolution path instead of the hosts
    entry.
  6. Built a new image with this change applied.
  7. Re-ran the same test and confirmed that:
    • the email send completed successfully;
    • the maildev server received and logged the message.

Screenshots / Logs (if applicable)

Checklist:

  • I have read and followed the contribution guidelines.
  • Disclosed any use of AI (see our policy)
  • I have updated the documentation accordingly.
  • All new and existing tests passed.
  • Successful build pnpm build
  • Translation keys pnpm i18n:extract
  • Database migration (if required)

Summary by CodeRabbit

  • Chores
    • Updated Next.js type generation path to align with the build output for more reliable type resolution.
    • Improved email service network connection handling to be more robust across SMTP hosts, reducing delivery failures and connection errors.

Review Change Stack

@0xSysR3ll 0xSysR3ll requested a review from a team as a code owner May 27, 2026 18:11
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 27, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 173f7494-be00-44db-bce5-4b5a59746ed0

📥 Commits

Reviewing files that changed from the base of the PR and between 044967e and 18c0d9b.

📒 Files selected for processing (2)
  • next-env.d.ts
  • server/lib/email/index.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • next-env.d.ts
  • server/lib/email/index.ts

📝 Walkthrough

Walkthrough

Updates Next.js env route type import to .next/types/... and adds a typed, conditional getSocket for Nodemailer that creates a raw TCP socket (via Node's net) and is used only when the SMTP host is not an IP address.

Changes

Next.js Type Definitions Path

Layer / File(s) Summary
Type import path alignment
next-env.d.ts
Routes type import updated from .next/dev/types/ to .next/types/ to reference the standard generated build output.

SMTP Custom Socket for /etc/hosts Support

Layer / File(s) Summary
Custom TCP socket with /etc/hosts support
server/lib/email/index.ts
Adds a typed getSocket helper that creates a TCP connection with net.createConnection, attaches one-time error, connect, and timeout handlers, returns { connection: socket } to Nodemailer, and is wired into the transport options only when the SMTP host is not an IP (net.isIP check).

Sequence Diagram

sequenceDiagram
  participant Nodemailer
  participant getSocket
  participant net_createConnection as net.createConnection
  participant SMTPServer as SMTP Server
  Nodemailer->>getSocket: request socket (host not IP)
  getSocket->>net_createConnection: create TCP connection to host:port
  net_createConnection->>SMTPServer: establish TCP connection
  SMTPServer-->>net_createConnection: socket connected
  net_createConnection-->>getSocket: socket ready
  getSocket-->>Nodemailer: return { connection: socket }
  Nodemailer->>SMTPServer: use returned socket for SMTP session
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 A curious rabbit taps the wire,
I roll a socket through the mire,
/etc/hosts now found its voice,
Mail connects and hearts rejoice,
Types aligned — the build's in choir.

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'fix(email): respect hosts file for SMTP connections' directly and clearly summarizes the main change—implementing custom socket handling for SMTP connections to honor system hosts file entries.
Linked Issues check ✅ Passed The code changes implement the core requirement from #3020: ensuring SMTP connections respect /etc/hosts and Docker extra_hosts entries by using custom socket handling for non-IP hostnames.
Out of Scope Changes check ✅ Passed All changes are scoped to the email SMTP functionality. The changes to next-env.d.ts (type path update) and server/lib/email/index.ts (custom socket implementation) are directly related to fixing the hosts file resolution issue.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
server/lib/email/index.ts (1)

49-49: Verify nodemailer getSocket integration and IP/hostname branching

  • nodemailer is pinned to 8.0.5, and the transport getSocket callback wiring matches the expected contract (getSocket(options, callback) -> callback(err) / callback(null, { connection })).
  • The conditional socket injection correctly disables getSocket for literal IPs and uses it for hostnames:
    getSocket: net.isIP(settings.options.smtpHost) ? undefined : getSocket,
  • Consider explicitly guarding against empty/undefined smtpHost so you don’t accidentally route through getSocket with an empty host value.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@server/lib/email/index.ts` at line 49, The transport wiring currently chooses
getSocket based on net.isIP(settings.options.smtpHost) but can mistakenly pass
getSocket when smtpHost is empty/undefined; update the condition used where
getSocket is assigned (the getSocket property for the nodemailer transport
creation) to explicitly check that settings.options.smtpHost is a non-empty
string and not an IP (e.g., ensure settings.options.smtpHost &&
!net.isIP(settings.options.smtpHost)) so getSocket is only set for valid
hostnames; keep the existing getSocket callback implementation and nodemailer
compatibility unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@server/lib/email/index.ts`:
- Around line 10-24: The getSocket function lacks a connection timeout; update
getSocket to call socket.setTimeout(...) (e.g., 10000 ms) after net.connect,
listen for the 'timeout' event and in that handler remove the 'error'/'connect'
listeners, destroy the socket, and invoke callback with a timeout Error; also
ensure you clear the timeout or remove the 'timeout' listener inside onConnect
and onError so you don't leak listeners or sockets. Target the getSocket
function and its onError/onConnect handlers to add the timeout setup and cleanup
logic.

---

Nitpick comments:
In `@server/lib/email/index.ts`:
- Line 49: The transport wiring currently chooses getSocket based on
net.isIP(settings.options.smtpHost) but can mistakenly pass getSocket when
smtpHost is empty/undefined; update the condition used where getSocket is
assigned (the getSocket property for the nodemailer transport creation) to
explicitly check that settings.options.smtpHost is a non-empty string and not an
IP (e.g., ensure settings.options.smtpHost &&
!net.isIP(settings.options.smtpHost)) so getSocket is only set for valid
hostnames; keep the existing getSocket callback implementation and nodemailer
compatibility unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9fb9ce4a-2a75-428b-9da7-af6fd800e70c

📥 Commits

Reviewing files that changed from the base of the PR and between c04172a and 044967e.

📒 Files selected for processing (2)
  • next-env.d.ts
  • server/lib/email/index.ts

Comment thread server/lib/email/index.ts
@0xSysR3ll 0xSysR3ll force-pushed the 0xsysr3ll/fix/nodemailer-docker-hosts-resolution branch from 044967e to 18c0d9b Compare May 27, 2026 18:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

/etc/hosts entry ignored when sending mail

1 participant