Postfix, Node.js, and SMTP: Receiving Emails with a Custom Domain

Abstract: Resolve Postfix connection refused errors and misconfigured local delivery for Node.js email integration by correcting interface binding and domain settings.

Created: 2026-08-29 by
This article explains how to configure Postfix on Ubuntu to accept incoming SMTP connections for a custom domain and route them to a Node.js application via local delivery. We address the common configuration errors that prevent external mail from reaching your server, specifically focusing on correct interface binding and destination domain handling.

Understanding the Architecture

To receive emails with a custom domain, your DNS must point the MX record to your server’s public IP address. When an external mail server attempts to deliver mail, it connects to your server on port 25 (or 587) using the Simple Mail Transfer Protocol (SMTP). Postfix acts as the recipient agent, validating the domain and deciding where to place the message. For integration with a Node.js application, the most reliable method is not to expose a raw socket directly to Postfix, but rather to use Postfix’s local delivery agent (LDA) or a relay transport to pass the email content to your script.

A frequent mistake in this setup involves misconfiguring the network interfaces. If you set inet_interfaces = loopback-only, Postfix will only listen on 127.0.0.1. This means external clients cannot connect, resulting in "Connection Refused" errors. Conversely, if you simply bind to all interfaces without proper restrictions, you risk becoming an open relay. The correct approach is to bind to the specific public IP address of your server or to all while restricting access via firewall rules and Postfix’s own access controls.

Configuring Postfix for Your Custom Domain

The core of receiving mail lies in telling Postfix that your custom domain is one it should accept. This is managed through the mydestination parameter in /etc/postfix/main.cf. However, there is a critical distinction between domains you host locally and domains you wish to process via an external agent like Node.js.

If you add your custom domain to mydestination, Postfix treats it as a local mailbox. It will attempt to deliver the mail to a system user or a virtual mailbox file. While this works for traditional email clients, it complicates integration with Node.js because you would need to parse mbox files or use a separate LDA. A cleaner architecture often involves treating the domain as a relayed destination or using virtual transports. However, for many simple Node.js setups, keeping the domain in mydestination and using a local delivery agent that pipes to stdin is the most straightforward path. Ensure that mydestination includes your hostname, localhost, and your custom domain:

mydestination = $myhostname, localhost.$mydomain, localhost, example.com

Replace example.com with your actual custom domain. After making changes, restart the service with sudo systemctl restart postfix.

Resolving Local Delivery Conflicts

You may encounter issues where Postfix tries to deliver mail externally despite your intentions, or vice versa. If you are seeing logs indicating "Local Delivery despite External Agent Configuration," check your transport_maps. These maps override default routing behavior. If you have defined a transport for your domain that points to a relayhost, Postfix will send the mail out instead of processing it locally. Remove any conflicting entries in /etc/postfix/transport for your receiving domain if you intend to handle them locally via Node.js.

For more details on troubleshooting these delivery conflicts, see Troubleshooting Postfix: Local Delivery despite External Agent Configuration.

Integrating Node.js with Postfix

Once Postfix accepts the mail, you need a mechanism to hand it off to your Node.js application. The standard Linux way to do this is by configuring a local delivery agent (LDA) such as procmail or a custom pipe in the virtual_alias_maps or mailbox_command. A robust method is to use a virtual alias that pipes the message to a script.

Create a script, for example /usr/local/bin/node-email-handler.sh, which executes your Node.js script. The script should read from standard input (stdin), which contains the raw email headers and body. Here is a basic structure for the shell wrapper:

#!/bin/bash
/usr/bin/node /path/to/your/email-handler.js < /dev/stdin

Ensure the script is executable with chmod +x /usr/local/bin/node-email-handler.sh. Then, configure Postfix to use this handler. You can define a virtual map in /etc/postfix/virtual:

@example.com pipe:nodehandler

And in main.cf:

virtual_alias_maps = hash:/etc/postfix/virtual
virtual_transport = local

After updating the virtual map, run sudo postmap /etc/postfix/virtual and restart Postfix. Now, when mail arrives for @example.com, Postfix will pipe it to your Node.js script.

Handling Dynamic IPs and Security

If your server uses a dynamic IP address, receiving mail can be challenging due to spam filters and blacklists. Many receiving servers reject mail from dynamic IPs because they are commonly associated with spam. To mitigate this, ensure your reverse DNS (PTR) record matches your hostname. Additionally, consider using a dedicated static IP for email services if possible.

For guidance on managing email delivery issues related to IP addresses, refer to Handling Email Delivery with Dynamic IP Addresses on Ubuntu Server using Postfix.

Security is also paramount. Do not leave Postfix open to the internet without authentication for sending. Since we are focusing on receiving, ensure that your Node.js application validates the sender and handles the email content securely to prevent injection attacks. Use TLS certificates to encrypt incoming connections if supported by your setup, adding smtpd_tls_security_level = may to main.cf.

Frequently Asked Questions

Why does my Node.js script not receive the full email?

Ensure that your shell wrapper correctly passes standard input to the Node.js process. If the script hangs, it might be waiting for EOF. Verify that the piping mechanism in Postfix is functioning by testing with sendmail locally first. Check the system logs at /var/log/mail.log for any errors during the delivery phase.

Can I use Port 587 for receiving emails?

Port 587 is primarily intended for mail submission from authenticated users (clients sending mail), not for receiving mail from other servers. Inter-server communication typically occurs on Port 25. Configure Postfix to listen on Port 25 for inbound mail and reserve Port 587 for outbound submission if needed.

How do I debug why Postfix rejects my domain?

Check the mydestination setting in main.cf to ensure your custom domain is listed. Also, verify that your DNS MX records are correctly pointing to your server’s IP. Use postconf -n to review your current configuration and look for syntax errors.

What if I want to store emails in a database instead of parsing them?

Your Node.js application can connect to a database upon startup. As the email is piped in via stdin, parse the MIME structure using a library like nodemailer’s built-in parser or mailparser. Insert the parsed data into your database within the script. This allows for scalable storage and retrieval.

Does changing inet_interfaces affect security?

Yes. Setting inet_interfaces = all exposes Postfix to all network interfaces. If your server has multiple IPs, ensure that only the intended public IP is accessible from the internet. Use firewall rules (like UFW or iptables) to restrict access to Port 25 and 587 to trusted networks or the entire internet as appropriate for your setup.

Latest News

How to Display Output of xterm Command in Terminal Screen using Cron

Resolve the inability to display xterm output in a terminal screen from cron by redirecting logs or using wall instead of insecure X11 workarounds.

Read More
Expose Local Server on VPS Preserving Real Client IPs (OS Level)

Resolve VPS logging showing only gateway IPs by configuring reverse proxies to forward real client addresses via X-Forwarded-For headers.

Read More
How to Clear Recent Files History in Linux without Deleting Actual Files?

Clear recent files history in Linux by deleting ~/.local/share/recently-used.xbel without removing the actual files.

Read More
Best HDD Copy Strategy: Manually Syncing and Rewriting Scratch

Resolve data drift between two 4TB hard drives by using rsync with the --delete flag to manually sync and rewrite scratch data for an exact mirror.

Read More
Understanding Bash Prompt Abbreviations: An Overview

Resolve repetitive typing errors by creating and persisting Bash aliases in the .bashrc file for improved command-line efficiency.

Read More
Free Tools and Methods to Log Real-Time Performance Details in Task Manager

Log real-time CPU and memory metrics to CSV files using Windows Performance Monitor Data Collector Sets to troubleshoot system slowness.

Read More
Contact Qatar Airways Customer Service: Phone Number, Help Center, and More

Resolve urgent Qatar Airways reservation issues like flight changes and baggage claims using the US phone number +1801-855-5905 or online self-service tools.

Read More
Windows 11: Alt Codes Displaying Wrong Characters - Solutions

Resolve Windows 11 Alt codes showing wrong characters by verifying the US keyboard layout and enabling Num Lock.

Read More
Run Programs with Elevated Privileges: A Comprehensive Guide

Eliminates the need to type sudo for frequent administrative tasks by configuring .bashrc aliases or functions.

Read More
Dynamically Changing Dates in Excel Formulas Using Cells

Eliminate manual date updates in Excel by using cell references to create dynamic formulas that automatically adjust calculations when input dates change.

Read More
Granting Edit Access to a Specific Excel Sheet in an Office 365 User Email ID-Based Login

Excel Online lacks native sheet-level permissions, so users must split workbooks or use worksheet protection to isolate edit access for specific tabs.

Read More
Creating Network Load on Local Wi-Fi from One PC

Generate sustained Wi-Fi bandwidth load from a single PC using a VM SFTP server to test router stability and throughput.

Read More
Changing the Default Editor for Batch Files in Windows 11's File Explorer

Resolve the issue of batch files opening in Notepad by changing the default editor to a preferred application like VS Code.

Read More
Gain WiFi Connection Minutes Before Losing it by Changing MAC Address

Bypass MAC address filtering to restore WiFi connectivity temporarily when a device is blocked by network administrators.

Read More
Photos Folders Turned Black: Troubleshooting Picture Applications on Windows

Resolve black screens in Windows Photos by resetting the app, updating graphics drivers, and repairing system files.

Read More
Troubleshooting High CPU Temperature Values: A Step-by-Step Guide

Resolve high CPU temperatures and thermal throttling by monitoring with Speedfan, cleaning dust from cooling components, and replacing degraded thermal paste.

Read More
Make cURL establish TLS connection with CA unknown

Resolve cURL TLS connection failures with unknown or self-signed certificates by using the --insecure flag to bypass CA validation.

Read More
Troubleshooting Incorrect Network Metrics Values in Grafana, Prometheus, InfluxDB, and Telegraf

Fix incorrect network metrics in Grafana, Prometheus, InfluxDB, and Telegraf by verifying interface selection, resolving unit mismatches, and handling counter resets.

Read More
Start Another Terminal Window (cmd.exe) Windows Repair/Troubleshoot

Provides step-by-step instructions to access the Windows Command Prompt via bootable media for advanced system repair and troubleshooting.

Read More
Thinkpad P1 Gen 6: Sudden Thunderbolt 3 Dock USB-C Charging Stopped Working

Resolve sudden Thunderbolt 3 dock USB-C charging and internet failure on ThinkPad P1 Gen 6 by updating firmware, resetting the dock, and adjusting power settings.

Read More
ASUS Windows 11 Laptop: Internet Connection Issue with Hotspot

Resolve ASUS Windows 11 laptop spinning wheel issue when connecting to mobile hotspot by resetting network stack, disabling IPv6, and adjusting power settings.

Read More
Developing iOS Project with Firebase: Logging in and Sending Push Notifications

Integrates Firebase to enable secure user authentication and push notifications in iOS applications.

Read More
Troubleshooting Bash Script with Suspected Issues of Spaces, Dashes, Filenames and Quoting

Resolve Bash script failures caused by word splitting, globbing, and special characters in filenames by applying proper quoting techniques.

Read More
Populating OneDrive Folder for Local Backup without Affecting Remote Files

Prevent OneDrive from deleting remote files during Windows reinstallation by unlinking the account or using symbolic links to isolate local data.

Read More
Force First Frame as Keyframe Without Re-encoding: A Quick Solution

Resolve inaccurate seeking and playback glitches by re-encoding video to ensure the first frame is a valid keyframe.

Read More
Find Information in Database Using WSL (Ubuntu) on Windows-10

Resolve database connection issues from WSL Ubuntu on Windows 10 by configuring client tools and network access to query remote or local servers.

Read More
Configuring a New Router with Different Networks: One Family, One Guest

Resolve IP conflicts and isolate guest traffic by configuring a second router with a distinct subnet via its WAN port.

Read More
Quickly Open Multiple Stock Websites with a Single Command

Solve the problem of manually opening multiple stock research websites by creating a single command to launch them simultaneously on Windows, macOS, or Linux.

Read More
Improved Adobe Acrobat Search Experience: Access Advanced Search with Ease

Access advanced search filters like case sensitivity and regex in Adobe Acrobat by clicking More Options in the Find bar.

Read More
Port Forwarding VM via OpenVPN: A Comprehensive Guide

Configure OpenVPN server and iptables to forward specific ports from VPN clients to a virtual machine's internal IP address.

Read More
Understanding Partitions in the 1980s: A Look Back at MS-DOS and Master Boot Record

Explains how the Master Boot Record and partition table enabled MS-DOS to manage multiple disk volumes on a single physical drive.

Read More
Windows 10 Enterprise: Keyboard Not Detected in Managed Organization with Admin Privileges

Resolve Windows 10 Enterprise keyboard detection failures caused by Group Policy restrictions, driver corruption, or USB enumeration errors.

Read More
Can't Find x86_64 Versions of Applications on MacOS arm64 (M1)

Resolve missing x86_64 app issues on M1 Macs by installing Rosetta 2 and reinstalling apps as universal binaries.

Read More
How to Hide Installation Source for an Android App

Manage Android app installation source visibility by using USB transfers or file managers to reduce browser traces and isolate data via work profiles.

Read More
Connecting Momentus 4200.2 ST9808210A Hard Drive via USB Cable

Resolve inability to access Seagate Momentus 4200.2 ST9808210A hard drive by connecting it via USB using a compatible SATA-to-USB adapter and configuring the disk in Windows.

Read More