{"id":1713,"date":"2025-11-11T20:01:31","date_gmt":"2025-11-11T17:01:31","guid":{"rendered":"https:\/\/www.dchost.com\/blog\/i-built-my-own-mail-server-postfix-dovecot-rspamd-and-the-calm-path-to-deliverability-with-ip-warm%e2%80%91up\/"},"modified":"2025-11-11T20:01:31","modified_gmt":"2025-11-11T17:01:31","slug":"i-built-my-own-mail-server-postfix-dovecot-rspamd-and-the-calm-path-to-deliverability-with-ip-warm%e2%80%91up","status":"publish","type":"post","link":"https:\/\/www.dchost.com\/blog\/en\/i-built-my-own-mail-server-postfix-dovecot-rspamd-and-the-calm-path-to-deliverability-with-ip-warm%e2%80%91up\/","title":{"rendered":"I Built My Own Mail Server: Postfix, Dovecot, rspamd, and the Calm Path to Deliverability (with IP Warm\u2011Up)"},"content":{"rendered":"<div class=\"dchost-blog-content-wrapper\"><p>So there I was, staring at a flood of logs on a late Tuesday evening, realizing I had built myself a perfectly functioning email server that nobody trusted yet. The messages were queued neatly, signed with DKIM, the SPF was crisp, DMARC was ready for inspection. But those first few emails still tiptoed into promotion tabs and sometimes even the void. If you\u2019ve ever tried to self\u2011host email, you know the feeling. It\u2019s like building a cozy caf\u00e9 and then wondering why the neighborhood hasn\u2019t discovered your perfect cappuccino.<\/p>\n<p>In this guide, I\u2019ll show you how I set up a calm, reliable email stack\u2014Postfix for sending, Dovecot for IMAP\/POP3, and rspamd for filtering\u2014and the deliverability work that actually moves the needle. We\u2019ll also walk through a practical IP warm\u2011up plan (the part many skip), because reputation is everything. I\u2019ll share the exact steps, the missteps I wish I\u2019d avoided, and the small tweaks that made a big difference. By the end, you\u2019ll have a working stack, a sensible deliverability workflow, and the confidence to send without the drama.<\/p>\n<div id=\"toc_container\" class=\"toc_transparent no_bullets\"><p class=\"toc_title\">\u0130&ccedil;indekiler<\/p><ul class=\"toc_list\"><li><a href=\"#Why_SelfHost_Email_at_All\"><span class=\"toc_number toc_depth_1\">1<\/span> Why Self\u2011Host Email at All?<\/a><\/li><li><a href=\"#The_Groundwork_DNS_Identity_and_Reputation_Before_a_Single_Byte\"><span class=\"toc_number toc_depth_1\">2<\/span> The Groundwork: DNS, Identity, and Reputation Before a Single Byte<\/a><\/li><li><a href=\"#VPS_Prep_Hostname_Time_Firewall_and_Updates\"><span class=\"toc_number toc_depth_1\">3<\/span> VPS Prep: Hostname, Time, Firewall, and Updates<\/a><\/li><li><a href=\"#Postfix_Your_Calm_Reliable_MTA\"><span class=\"toc_number toc_depth_1\">4<\/span> Postfix: Your Calm, Reliable MTA<\/a><ul><li><a href=\"#Install_and_basic_layout\"><span class=\"toc_number toc_depth_2\">4.1<\/span> Install and basic layout<\/a><\/li><li><a href=\"#Core_Postfix_config\"><span class=\"toc_number toc_depth_2\">4.2<\/span> Core Postfix config<\/a><\/li><li><a href=\"#Submission_and_smtps_services\"><span class=\"toc_number toc_depth_2\">4.3<\/span> Submission and smtps services<\/a><\/li><\/ul><\/li><li><a href=\"#Dovecot_IMAP_That_Feels_Effortless\"><span class=\"toc_number toc_depth_1\">5<\/span> Dovecot: IMAP That Feels Effortless<\/a><ul><li><a href=\"#Install_and_basic_config\"><span class=\"toc_number toc_depth_2\">5.1<\/span> Install and basic config<\/a><\/li><\/ul><\/li><li><a href=\"#rspamd_Smart_Fast_and_Surprisingly_Fun\"><span class=\"toc_number toc_depth_1\">6<\/span> rspamd: Smart, Fast, and Surprisingly Fun<\/a><ul><li><a href=\"#Install_and_wire_up_milter\"><span class=\"toc_number toc_depth_2\">6.1<\/span> Install and wire up milter<\/a><\/li><li><a href=\"#DKIM_keys_and_signing\"><span class=\"toc_number toc_depth_2\">6.2<\/span> DKIM keys and signing<\/a><\/li><li><a href=\"#Greylisting_RBLs_and_rate_limiting\"><span class=\"toc_number toc_depth_2\">6.3<\/span> Greylisting, RBLs, and rate limiting<\/a><\/li><\/ul><\/li><li><a href=\"#TLS_That_Sticks_Certificates_and_Ciphers_Without_the_Drama\"><span class=\"toc_number toc_depth_1\">7<\/span> TLS That Sticks: Certificates and Ciphers Without the Drama<\/a><\/li><li><a href=\"#DNS_Records_That_Earn_Trust\"><span class=\"toc_number toc_depth_1\">8<\/span> DNS Records That Earn Trust<\/a><\/li><li><a href=\"#Testing_the_Plumbing_Before_Hitting_Send\"><span class=\"toc_number toc_depth_1\">9<\/span> Testing the Plumbing Before Hitting Send<\/a><\/li><li><a href=\"#Deliverability_The_Part_That_Actually_Decides_Your_Fate\"><span class=\"toc_number toc_depth_1\">10<\/span> Deliverability: The Part That Actually Decides Your Fate<\/a><\/li><li><a href=\"#IP_WarmUp_A_Calm_Realistic_Plan\"><span class=\"toc_number toc_depth_1\">11<\/span> IP Warm\u2011Up: A Calm, Realistic Plan<\/a><\/li><li><a href=\"#Security_Dont_Invite_Trouble_to_the_Party\"><span class=\"toc_number toc_depth_1\">12<\/span> Security: Don\u2019t Invite Trouble to the Party<\/a><\/li><li><a href=\"#Logs_Metrics_and_Sanity_Checks\"><span class=\"toc_number toc_depth_1\">13<\/span> Logs, Metrics, and Sanity Checks<\/a><\/li><li><a href=\"#Automation_and_Reproducibility_So_You_Can_Sleep\"><span class=\"toc_number toc_depth_1\">14<\/span> Automation and Reproducibility (So You Can Sleep)<\/a><\/li><li><a href=\"#A_Few_RealWorld_Troubleshooting_Stories\"><span class=\"toc_number toc_depth_1\">15<\/span> A Few Real\u2011World Troubleshooting Stories<\/a><\/li><li><a href=\"#Going_Beyond_the_Basics_Sieve_Aliases_and_NicetoHaves\"><span class=\"toc_number toc_depth_1\">16<\/span> Going Beyond the Basics: Sieve, Aliases, and Nice\u2011to\u2011Haves<\/a><\/li><li><a href=\"#Documentation_Youll_Thank_Yourself_For\"><span class=\"toc_number toc_depth_1\">17<\/span> Documentation You\u2019ll Thank Yourself For<\/a><\/li><li><a href=\"#WrapUp_A_Calm_Mailbox_Is_Built_Not_Bought\"><span class=\"toc_number toc_depth_1\">18<\/span> Wrap\u2011Up: A Calm Mailbox Is Built, Not Bought<\/a><\/li><li><a href=\"#Quick_Reference_Handy_Links_Youll_Actually_Use\"><span class=\"toc_number toc_depth_1\">19<\/span> Quick Reference: Handy Links You\u2019ll Actually Use<\/a><\/li><\/ul><\/div>\n<h2 id=\"section-1\"><span id=\"Why_SelfHost_Email_at_All\">Why Self\u2011Host Email at All?<\/span><\/h2>\n<p>I get this question a lot. When a SaaS sender can get you up and running fast, why bother? For me, it\u2019s about control and craft. Self\u2011hosting email lets you understand what\u2019s under the hood, tune it to your needs, and keep your data where you want it. It also teaches you a ton about DNS, TLS, authentication, and how inbox providers actually judge your messages.<\/p>\n<p>Here\u2019s the thing: email is not just software. It\u2019s a reputation engine. And reputation moves slowly. When you run your own MTA (Mail Transfer Agent), you\u2019re responsible for how that reputation is built, nurtured, and protected. That can be incredibly empowering when you do it right. But it rewards patience and good habits.<\/p>\n<h2 id=\"section-2\"><span id=\"The_Groundwork_DNS_Identity_and_Reputation_Before_a_Single_Byte\">The Groundwork: DNS, Identity, and Reputation Before a Single Byte<\/span><\/h2>\n<p>Before you install anything, set your foundation. Think of DNS and identity as your caf\u00e9\u2019s signage and permits. Skip them and you\u2019ll wonder why nobody walks through the door.<\/p>\n<p>Start with a clean domain. If the domain has a history of spam complaints, consider using a new subdomain like <strong>mail.example.com<\/strong> or <strong>mg.example.com<\/strong> for outbound traffic. Make sure your <a href=\"https:\/\/www.dchost.com\/vps\">VPS<\/a> provider gives you control over rDNS (PTR). Your reverse DNS must resolve to your server\u2019s hostname, and that hostname should resolve back to the IP. Forward and reverse resolution should match; mailbox providers love that neat loop. If your provider doesn\u2019t allow rDNS, pick one that does\u2014this detail matters.<\/p>\n<p>Then line up your email authentication trio: SPF, DKIM, and DMARC. SPF says who\u2019s allowed to send for your domain. DKIM signs the message so it can\u2019t be tampered with. DMARC ties SPF and DKIM to your domain\u2019s policy and reporting. If you want to lean into brand trust later, BIMI can help, but only after your core reputation is healthy. When you\u2019re ready for the deeper end of the pool, I wrote a <a href=\"https:\/\/www.dchost.com\/blog\/en\/gelismis-dmarc-ve-bimi-rua-ruf-raporlarindan-marka-gostergesine-nasil-yol-alinir\/\">friendly playbook for advanced DMARC, RUA\/RUF analysis, and BIMI<\/a> that pairs nicely with this guide.<\/p>\n<p>Two more signals worth your time: MTA\u2011STS and TLS\u2011RPT. MTA\u2011STS lets you declare that you expect TLS for SMTP, and TLS\u2011RPT collects reports when that doesn\u2019t happen. They don\u2019t unlock instant deliverability, but they round out a story of a careful sender who values secure transport.<\/p>\n<h2 id=\"section-3\"><span id=\"VPS_Prep_Hostname_Time_Firewall_and_Updates\">VPS Prep: Hostname, Time, Firewall, and Updates<\/span><\/h2>\n<p>I\u2019ll assume a Debian or Ubuntu VPS, but the concepts apply broadly. Pick a stable image. Set your hostname to match what you intend to present via SMTP\u2014something like <strong>mail.example.com<\/strong>. Make sure DNS A\/AAAA records and PTR\/rDNS are in place first. Then sync time with NTP; mismatched clocks cause weird TLS and DKIM signatures to fail. Update your packages, enable a firewall (UFW or nftables), and open only what you need: 25 (SMTP), 587 (submission), 465 (smtps, if you prefer implicit TLS), 993 (IMAPS), and maybe 995 if you still want POP3S. I tend to skip plaintext 110\/143 entirely.<\/p>\n<p>One more thing that quietly matters: IPv6. If you have a clean IPv6 allocation and working reverse DNS, great\u2014enable it. If your provider\u2019s IPv6 rDNS is broken or non\u2011configurable, stick to IPv4 for outbound at first. A broken IPv6 path can throttle your deliverability without obvious errors. I learned that one the hard way after three quiet days and a lot of head scratching.<\/p>\n<h2 id=\"section-4\"><span id=\"Postfix_Your_Calm_Reliable_MTA\">Postfix: Your Calm, Reliable MTA<\/span><\/h2>\n<p>Postfix is the heart of this stack. I love it because it\u2019s predictable and well\u2011documented. The defaults are sensible, but we\u2019ll turn on the things that matter for a modern, authenticated sender.<\/p>\n<h3><span id=\"Install_and_basic_layout\">Install and basic layout<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">apt update &amp;&amp; apt install -y postfix postfix-pcre libsasl2-modules\n<\/code><\/pre>\n<p>Choose \u201cInternet Site\u201d during installation and set your system mail name to your primary mail hostname. You can always change it later in <strong>\/etc\/postfix\/main.cf<\/strong>.<\/p>\n<h3><span id=\"Core_Postfix_config\">Core Postfix config<\/span><\/h3>\n<p>Here\u2019s a practical starting point. Adjust domains, hostnames, and certificates as needed.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># \/etc\/postfix\/main.cf\nmyhostname = mail.example.com\nmyorigin = \/etc\/mailname\nmydestination = localhost\nrelay_domains =\ninternet_protocols = ipv4\n\n# Network\ninet_interfaces = all\ninet_protocols = all\nsmtpd_banner = $myhostname ESMTP\n\n# TLS for inbound\nsmtpd_tls_cert_file = \/etc\/letsencrypt\/live\/mail.example.com\/fullchain.pem\nsmtpd_tls_key_file  = \/etc\/letsencrypt\/live\/mail.example.com\/privkey.pem\nsmtpd_tls_security_level = may\nsmtpd_tls_protocols = !SSLv2, !SSLv3\nsmtpd_tls_mandatory_protocols = TLSv1.2 TLSv1.3\nsmtpd_tls_auth_only = yes\n\n# TLS for outbound\nsmtp_tls_security_level = may\nsmtp_tls_loglevel = 1\nsmtp_tls_CAfile = \/etc\/ssl\/certs\/ca-certificates.crt\n\n# SASL auth via Dovecot\nsmtpd_sasl_type = dovecot\nsmtpd_sasl_path = private\/auth\nsmtpd_sasl_auth_enable = yes\nsmtpd_sasl_security_options = noanonymous\n\n# Restrict who can use submission\nsmtpd_recipient_restrictions =\n    permit_mynetworks,\n    permit_sasl_authenticated,\n    reject_unauth_destination\n\n# HELO hygiene\nsmtpd_helo_required = yes\nsmtpd_helo_restrictions =\n    reject_invalid_helo_hostname,\n    reject_non_fqdn_helo_hostname\n\n# Virtual domains\nvirtual_mailbox_domains = example.com\nvirtual_transport = lmtp:unix:private\/dovecot-lmtp\nvirtual_mailbox_maps = ldap:\/etc\/postfix\/ldap-users.cf # or hash\/sql if you prefer\nvirtual_alias_maps = hash:\/etc\/postfix\/virtual\n\n# Performance \/ rate controls (tune for warm-up)\nmaximal_queue_lifetime = 3d\nbounce_queue_lifetime  = 3d\nsmtp_destination_concurrency_limit = 3\nsmtp_destination_rate_delay = 1s\n<\/code><\/pre>\n<p>That last bit on concurrency and rate delay is a gentle handbrake that helps when you\u2019re warming up your IP. Don\u2019t go overboard; start conservative and observe how large providers respond.<\/p>\n<h3><span id=\"Submission_and_smtps_services\">Submission and smtps services<\/span><\/h3>\n<p>Enable authenticated submission on 587 (and 465 if you want implicit TLS) so your users or apps can send securely.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># \/etc\/postfix\/master.cf\nsubmission inet n       -       y       -       -       smtpd\n  -o syslog_name=postfix\/submission\n  -o smtpd_tls_security_level=encrypt\n  -o smtpd_sasl_auth_enable=yes\n  -o smtpd_client_restrictions=permit_sasl_authenticated,reject\n\nsmtps      inet n       -       y       -       -       smtpd\n  -o syslog_name=postfix\/smtps\n  -o smtpd_tls_wrappermode=yes\n  -o smtpd_sasl_auth_enable=yes\n  -o smtpd_client_restrictions=permit_sasl_authenticated,reject\n<\/code><\/pre>\n<p>Reload Postfix when you\u2019re ready:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">systemctl restart postfix\n<\/code><\/pre>\n<p>If you want to go deeper (and you should), the <a href=\"https:\/\/www.postfix.org\/\" rel=\"nofollow noopener\" target=\"_blank\">Postfix official docs<\/a> are a goldmine. I\u2019ve lost count of how many tiny \u201caha\u201d moments I\u2019ve had there.<\/p>\n<h2 id=\"section-5\"><span id=\"Dovecot_IMAP_That_Feels_Effortless\">Dovecot: IMAP That Feels Effortless<\/span><\/h2>\n<p>Dovecot handles mailbox storage and authentication. I like to think of it as the quiet concierge who keeps everything tidy and fast. It also offers LMTP delivery and Sieve filtering\u2014two features that make the whole experience feel polished.<\/p>\n<h3><span id=\"Install_and_basic_config\">Install and basic config<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">apt install -y dovecot-imapd dovecot-lmtpd dovecot-sieve dovecot-managesieved\n<\/code><\/pre>\n<p>Set TLS, mail location, and auth. For virtual users, a common pattern is to create a <strong>vmail<\/strong> user and use Maildir storage.<\/p>\n<pre class=\"language-nginx line-numbers\"><code class=\"language-nginx\"># \/etc\/dovecot\/dovecot.conf\nprotocols = imap lmtp\nlisten = *,::\n\n# TLS (use the same cert as Postfix)\nssl = required\nssl_cert = \nssl_key  = \nssl_min_protocol = TLSv1.2\n\n# Mail storage\nmail_home = \/var\/vmail\/%d\/%n\nmail_location = maildir:~\/Maildir\nfirst_valid_uid = 150\nfirst_valid_gid = 8\n\n# Auth\nauth_mechanisms = plain login scram-sha-256\npassdb {\n  driver = passwd-file\n  args = scheme=SHA512-CRYPT username_format=%u \/etc\/dovecot\/passwd\n}\nuserdb {\n  driver = static\n  args = uid=vmail gid=vmail home=\/var\/vmail\/%d\/%n\n}\n\n# LMTP for local delivery from Postfix\nservice lmtp {\n  unix_listener \/var\/spool\/postfix\/private\/dovecot-lmtp {\n    mode = 0600\n    user = postfix\n    group = postfix\n  }\n}\n\n# SASL socket for Postfix submission\nservice auth {\n  unix_listener \/var\/spool\/postfix\/private\/auth {\n    mode = 0660\n    user = postfix\n    group = postfix\n  }\n}\n<\/code><\/pre>\n<p>Create the vmail user and directories, then add users to <strong>\/etc\/dovecot\/passwd<\/strong> with hashed passwords. Dovecot\u2019s <strong>doveadm pw<\/strong> helps generate secure hashes.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">adduser --system --group --home \/var\/vmail vmail\nmkdir -p \/var\/vmail\nchown -R vmail:vmail \/var\/vmail\n\n# generate a hash\ndoveadm pw -s SHA512-CRYPT\n<\/code><\/pre>\n<p>Restart and test IMAP connectivity. I still use <strong>openssl s_client -connect mail.example.com:993<\/strong> just to peek at certificates and ciphers. Old habit, still useful.<\/p>\n<p>When you\u2019re ready to dive deeper, the <a href=\"https:\/\/doc.dovecot.org\/\" rel=\"nofollow noopener\" target=\"_blank\">Dovecot documentation<\/a> is excellent and practical.<\/p>\n<h2 id=\"section-6\"><span id=\"rspamd_Smart_Fast_and_Surprisingly_Fun\">rspamd: Smart, Fast, and Surprisingly Fun<\/span><\/h2>\n<p>I remember flipping the switch on rspamd for the first time and watching spam scores roll in with laser\u2011like detail. It\u2019s fast, modular, and integrates beautifully with Postfix via milter\u2014so much so that it feels like it was designed for this exact trio.<\/p>\n<h3><span id=\"Install_and_wire_up_milter\">Install and wire up milter<\/span><\/h3>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">apt install -y rspamd redis-server\n<\/code><\/pre>\n<p>Enable Postfix milter integration so rspamd can scan inbound and (optionally) sign outbound via DKIM.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\"># \/etc\/postfix\/main.cf (continued)\nsmtpd_milters = inet:127.0.0.1:11332\nnon_smtpd_milters = $smtpd_milters\nmilter_default_action = accept\nmilter_protocol = 6\n<\/code><\/pre>\n<p>Restart both:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">systemctl restart rspamd postfix\n<\/code><\/pre>\n<h3><span id=\"DKIM_keys_and_signing\">DKIM keys and signing<\/span><\/h3>\n<p>rspamd makes DKIM easy. Generate a selector and publish the public key in DNS.<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">rspamadm dkim_keygen -b 2048 -s mail -d example.com -k \/var\/lib\/rspamd\/dkim\/example.com.mail.key &gt; \/var\/lib\/rspamd\/dkim\/example.com.mail.pub\nchown -R _rspamd:_rspamd \/var\/lib\/rspamd\/dkim\n<\/code><\/pre>\n<p>Then configure signing in <strong>\/etc\/rspamd\/local.d\/dkim_signing.conf<\/strong>:<\/p>\n<pre class=\"language-bash line-numbers\"><code class=\"language-bash\">domain { example.com { selector = &quot;mail&quot;; path = &quot;\/var\/lib\/rspamd\/dkim\/example.com.mail.key&quot;; } }\nallow_envfrom_empty = true\nsign_authenticated = true\nsign_local = true\n<\/code><\/pre>\n<p>While you\u2019re there, consider enabling ARC and DMARC reporting modules. ARC can help in forwarders, and rspamd\u2019s DMARC checks give you an extra layer of insight. The <a href=\"https:\/\/rspamd.com\/doc\/\" rel=\"nofollow noopener\" target=\"_blank\">rspamd documentation<\/a> has practical examples that translate well to production.<\/p>\n<h3><span id=\"Greylisting_RBLs_and_rate_limiting\">Greylisting, RBLs, and rate limiting<\/span><\/h3>\n<p>I tend to enable a modest greylist window and a few conservative DNSBLs. rspamd\u2019s default rules are already strong, so resist the urge to pile on every blocklist under the sun. Less is more, as false positives can burn trust quickly. For outbound, rspamd\u2019s rate limit module is a handy guardrail when warming up. You can also lean on Postfix destination concurrency and rate delays to keep things smooth.<\/p>\n<h2 id=\"section-7\"><span id=\"TLS_That_Sticks_Certificates_and_Ciphers_Without_the_Drama\">TLS That Sticks: Certificates and Ciphers Without the Drama<\/span><\/h2>\n<p>Your mail stack should present consistent, trusted TLS. I usually use Let\u2019s Encrypt for the server certificate and set it for Postfix and Dovecot. Make sure the certificate common name or SAN includes the exact hostname you advertise in SMTP (that <strong>myhostname<\/strong> in Postfix) and IMAP. Rotate and reload on renewal\u2014cron or systemd timers make it hands\u2011off.<\/p>\n<p>If you\u2019re wondering about DV vs OV\/EV for mail: in practice, DV is usually enough for SMTP and IMAP. If your compliance or customer trust story demands more, I walked through <a href=\"https:\/\/www.dchost.com\/blog\/en\/dv-ov-ev-ve-wildcard-ssl-arasinda-kaybolmadan-e%E2%80%91ticaret-ve-saaste-hangi-sertifika-ne-zaman\/\">choosing the right certificate type for real\u2011world hosting<\/a>. Apply the same thinking to mail: pick the certificate that matches your risk, brand, and budget.<\/p>\n<h2 id=\"section-8\"><span id=\"DNS_Records_That_Earn_Trust\">DNS Records That Earn Trust<\/span><\/h2>\n<p>Let\u2019s sketch the essentials you want published before sending anything at scale.<\/p>\n<p>For SPF, keep it tight. If Postfix is your only sender, something like <strong>v=spf1 a:mail.example.com -all<\/strong> is perfect. For DKIM, publish the <strong>mail._domainkey.example.com<\/strong> TXT with the rspamd public key. For DMARC, start with <strong>p=none<\/strong> and reporting: <strong>v=DMARC1; p=none; rua=mailto:dmarc@example.com; ruf=mailto:dmarc-forensic@example.com; fo=1<\/strong>. Watch reports for a week or two, then move to <strong>quarantine<\/strong> and then <strong>reject<\/strong> once you\u2019re confident. If you want a deeper, friendlier strategy to go beyond p=none, see my <a href=\"https:\/\/www.dchost.com\/blog\/en\/gelismis-dmarc-ve-bimi-rua-ruf-raporlarindan-marka-gostergesine-nasil-yol-alinir\/\">advanced DMARC and BIMI playbook<\/a>.<\/p>\n<p>Don\u2019t forget PTR (reverse DNS) for your sending IP, MTA\u2011STS (a simple TXT and HTTPS\u2011served policy file), and TLS\u2011RPT (a TXT that announces where providers can send TLS failure reports). These small moves paint a picture of a careful sender.<\/p>\n<h2 id=\"section-9\"><span id=\"Testing_the_Plumbing_Before_Hitting_Send\">Testing the Plumbing Before Hitting Send<\/span><\/h2>\n<p>Before inviting real humans into the story, I run a handful of tests. Send yourself a message from the server to a few seed accounts on major providers. Look closely at the headers: <strong>Authentication\u2011Results<\/strong> tells you whether SPF, DKIM, and DMARC aligned. If something looks off, it usually comes down to a DNS typo, clock skew, wrong DKIM selector in the header, or reverse DNS mismatch.<\/p>\n<p>I also nudge the SMTP handshake by hand. A quick <strong>openssl s_client -starttls smtp -connect mail.example.com:25<\/strong> is old\u2011school but still golden for verifying TLS. For outbound, queue management is your friend: <strong>postqueue -p<\/strong> to peek, <strong>postqueue -f<\/strong> to flush, and <strong>postsuper -d ALL deferred<\/strong> when you need a clean slate after a config mistake.<\/p>\n<h2 id=\"section-10\"><span id=\"Deliverability_The_Part_That_Actually_Decides_Your_Fate\">Deliverability: The Part That Actually Decides Your Fate<\/span><\/h2>\n<p>Now the honest part. Deliverability is a trust game, and that trust is measured by engagement and consistency. If the first messages you send are cold blasts to old lists, your IP will be scolded like a kid who barged into the wrong classroom. Start small, start warm.<\/p>\n<p>In my experience, three things move the needle most early on. First, send to people who already know you: transactional emails, password resets, and real conversations. Second, segment by domain and watch responses\u2014Gmail and Outlook have their own rhythms. Third, keep your content simple at first. Avoid heavy images and trackers. Real, clear text with a sensible link tends to land better while your reputation is young.<\/p>\n<p>Handle bounces with care. Hard bounces should be removed fast. Soft bounces deserve a second chance, then a timeout. If you\u2019re sending newsletters, use engagement pruning: if someone hasn\u2019t opened in a while, slow down and then pause. I\u2019ve seen reputation recover dramatically by removing the bottom 10\u201320% of inactive recipients.<\/p>\n<h2 id=\"section-11\"><span id=\"IP_WarmUp_A_Calm_Realistic_Plan\">IP Warm\u2011Up: A Calm, Realistic Plan<\/span><\/h2>\n<p>Think of IP warm\u2011up like breaking in a new pair of boots: short walks first, then longer ones. If you sprint out of the gate, blisters are guaranteed.<\/p>\n<p>Here\u2019s a simple pattern I\u2019ve used repeatedly. For the first few days, send only transactional or high\u2011trust emails. If you run an app, this happens naturally. If not, pick a few internal accounts and partners, and have them reply. Replies are a strong positive signal. During the first week, keep daily volume in the hundreds, not thousands. Spread it across the day. Avoid spikes. By the second week, gently double the volume, but watch bounces and spam placement like a hawk. If you see a provider getting grumpy\u2014deferred deliveries, soft bounces, or an uptick in spam foldering\u2014pause, scale back for that domain, and resume slowly.<\/p>\n<p>Two tricks that help a lot: throttle by domain and schedule. In Postfix, the <strong>smtp_destination_concurrency_limit<\/strong> and <strong>smtp_destination_rate_delay<\/strong> settings give you per\u2011destination pacing. You can also create transport maps for big providers to apply specific throttles. And don\u2019t send large batches at the top of the hour\u2014spread them out to look more human. One of my clients cut spam foldering in half simply by staggering sends and tightening their bounce handling.<\/p>\n<p>And yes, keep the content helpful and personal. Few things beat a short, clear email that actually gets a reply. Warm\u2011up is about building a reputation for being wanted in the inbox. Value signals matter more than volume.<\/p>\n<h2 id=\"section-12\"><span id=\"Security_Dont_Invite_Trouble_to_the_Party\">Security: Don\u2019t Invite Trouble to the Party<\/span><\/h2>\n<p>Lock down your submission ports. Strong passwords or, even better, long randomly generated ones. Consider enabling fail2ban to watch for authentication abuse. For admin surfaces\u2014like the rspamd web UI\u2014put them behind your VPN or protect with client certificates. If that sounds interesting, I shared a step\u2011by\u2011step on <a href=\"https:\/\/www.dchost.com\/blog\/en\/yonetim-panellerini-mtls-ile-nasil-kale-gibi-korursun-nginxte-istemci-sertifikalari-adim-adim\/\">protecting panels with mTLS on Nginx<\/a> that fits perfectly here. The day I put mTLS in front of internal dashboards was the day I stopped worrying about brute\u2011force noise.<\/p>\n<p>On the Postfix side, don\u2019t be shy with <strong>smtpd_helo_restrictions<\/strong> and <strong>smtpd_client_restrictions<\/strong>. Require FQDN HELO\/EHLO, reject non\u2011FQDN senders, and guard submission to authenticated clients only. For Dovecot, disable plaintext auth unless under TLS, and stick to modern ciphers. And always, always keep your OS patched. Email stacks age quickly in the eyes of scanners.<\/p>\n<h2 id=\"section-13\"><span id=\"Logs_Metrics_and_Sanity_Checks\">Logs, Metrics, and Sanity Checks<\/span><\/h2>\n<p>Deliverability lives in your logs. I keep a split view open during warm\u2011up: Postfix logs to watch queue behavior, rspamd logs for spam scores, and Dovecot logs for auth patterns. You\u2019ll quickly spot misaligned DKIM, DMARC failures, or a rogue client battering your submission port. When stuff goes sideways, it usually shows up as a deferral trend before it becomes a full\u2011blown block.<\/p>\n<p>Make a habit of reading headers of sample messages received at major providers. The <strong>Authentication\u2011Results<\/strong> section tells you the truth about SPF, DKIM, and DMARC alignment. Google\u2019s and Microsoft\u2019s postmaster tools are helpful, but even without them, you can steer with good logs and a handful of seed inboxes.<\/p>\n<h2 id=\"section-14\"><span id=\"Automation_and_Reproducibility_So_You_Can_Sleep\">Automation and Reproducibility (So You Can Sleep)<\/span><\/h2>\n<p>The first time I hand\u2011built a mail server, I felt like a magician. The second time, I realized I needed a runbook. The third time, I wrote Ansible roles and never looked back. If you plan to maintain this, aim for reproducible builds. Automate user provisioning, DKIM key generation, and safe restarts. You don\u2019t want to solve the same tiny puzzle three times in a row.<\/p>\n<p>If you\u2019re into clean infrastructure flows, here\u2019s a story about <a href=\"https:\/\/www.dchost.com\/blog\/en\/bulutun-ilk-nefesi-cloud%E2%80%91init-ve-ansible-ile-tekrar-uretilebilir-vps-nasil-kurulur\/\">how I use cloud\u2011init and Ansible for first\u2011boot hardening<\/a>. And for the DNS side, I\u2019ve leaned on <a href=\"https:\/\/www.dchost.com\/blog\/en\/terraform-ile-vps-ve-dns-otomasyonu-cloudflare-proxmox-openstack-ve-sifir-kesinti-dagitim-nasil-bir-araya-gelir\/\">automating DNS and VPS provisioning with Terraform and Cloudflare<\/a> to keep SPF\/DKIM\/DMARC consistent across environments. Your future self will thank you when you rotate a key or move IPs.<\/p>\n<h2 id=\"section-15\"><span id=\"A_Few_RealWorld_Troubleshooting_Stories\">A Few Real\u2011World Troubleshooting Stories<\/span><\/h2>\n<p>One time, Gmail decided my transactional receipts looked \u201cpromotional\u201d for three days. Nothing changed in our stack\u2014same IP, same DKIM, same template. What fixed it? We stopped sending receipts at exactly the minute after the hour, added a tiny text\u2011only intro line, and asked a handful of users to reply if something looked off. The pattern normalized. The lesson: technical correctness and human signals both matter.<\/p>\n<p>Another time, a client\u2019s DKIM kept failing only at one provider. Turned out the DNS host silently truncated the DKIM TXT record because it was too long for their UI. We switched to a split TXT with proper quoting and it was instantly green. When DKIM fails intermittently, suspect DNS formatting first.<\/p>\n<p>And then there was the sneaky IPv6 rDNS with a stale hostname. Outbound connections preferred IPv6, but the PTR pointed to the old server. Everything looked fine on IPv4. The fix was either forcing IPv4 for a bit or getting rDNS updated. The moral: check both stacks, not just one.<\/p>\n<h2 id=\"section-16\"><span id=\"Going_Beyond_the_Basics_Sieve_Aliases_and_NicetoHaves\">Going Beyond the Basics: Sieve, Aliases, and Nice\u2011to\u2011Haves<\/span><\/h2>\n<p>Once your core is steady, sprinkle the quality\u2011of\u2011life upgrades. Dovecot\u2019s Sieve filtering lets users sort mail into folders automatically\u2014great for billing, notifications, and newsletters. Postfix aliases make role accounts easy\u2014<strong>support@example.com<\/strong> routing to a shared mailbox is a common pattern. If you run webmail, keep it separate from your MTA\/IMAP stack for simplicity and security, and consider rate limiting login attempts at the reverse proxy.<\/p>\n<p>If you plan bulk sends, I like using separate subdomains and signing keys for bulk vs transactional traffic. It\u2019s cleaner for reputation and makes DMARC reports easier to interpret. Later, if you pursue BIMI, that neatly separates the brand assets, too.<\/p>\n<h2 id=\"section-17\"><span id=\"Documentation_Youll_Thank_Yourself_For\">Documentation You\u2019ll Thank Yourself For<\/span><\/h2>\n<p>Write down three things: how you create a new mailbox (end\u2011to\u2011end), how you rotate a DKIM key, and how you handle a surge in soft bounces at one provider. Those runbooks cut resolution time dramatically. Pair them with simple dashboards or log queries that show deferred vs delivered counts per domain. When the queue whispers, you\u2019ll hear it sooner.<\/p>\n<h2 id=\"section-18\"><span id=\"WrapUp_A_Calm_Mailbox_Is_Built_Not_Bought\">Wrap\u2011Up: A Calm Mailbox Is Built, Not Bought<\/span><\/h2>\n<p>If you remember nothing else from this guide, remember this: self\u2011hosting email is about telling a consistent, trustworthy story\u2014technically and humanly. The software stack\u2014Postfix, Dovecot, rspamd\u2014gets you a sturdy chassis. DNS, TLS, SPF\/DKIM\/DMARC give you identity and guardrails. Deliverability and IP warm\u2011up build your reputation, one message at a time. None of it is magic. It\u2019s habits.<\/p>\n<p>Start with a clean domain, set rDNS right, keep your TLS steady, and sign every message. Send to people who want to hear from you, observe how providers respond, and adjust with empathy. If you automate your setup and document your playbook, you\u2019ll sleep better and recover faster from the occasional wobble. And when you\u2019re ready to go further with trust and brand signals, the <a href=\"https:\/\/www.dchost.com\/blog\/en\/gelismis-dmarc-ve-bimi-rua-ruf-raporlarindan-marka-gostergesine-nasil-yol-alinir\/\">advanced DMARC and BIMI guide<\/a> is there for you.<\/p>\n<p>Hope this was helpful! If you have a story about finally seeing your emails land where they belong, I\u2019d love to hear it. Until then\u2014steady sends, clean logs, and inboxes that smile back.<\/p>\n<h2 id=\"section-19\"><span id=\"Quick_Reference_Handy_Links_Youll_Actually_Use\">Quick Reference: Handy Links You\u2019ll Actually Use<\/span><\/h2>\n<p>Official docs if you want to go deep without detours:<\/p>\n<p><a href=\"https:\/\/www.postfix.org\/\" rel=\"nofollow noopener\" target=\"_blank\">Postfix official docs<\/a> \u2014 for transport maps, TLS tuning, and queue behavior<br \/>\n<a href=\"https:\/\/doc.dovecot.org\/\" rel=\"nofollow noopener\" target=\"_blank\">Dovecot documentation<\/a> \u2014 for auth backends, Sieve, and LMTP<br \/>\n<a href=\"https:\/\/rspamd.com\/doc\/\" rel=\"nofollow noopener\" target=\"_blank\">rspamd documentation<\/a> \u2014 for DKIM\/ARC, rate limits, and scoring<\/p>\n<p>And for the broader hosting context around this stack, these pieces fit neatly alongside your mail server:<\/p>\n<p><a href=\"https:\/\/www.dchost.com\/blog\/en\/terraform-ile-vps-ve-dns-otomasyonu-cloudflare-proxmox-openstack-ve-sifir-kesinti-dagitim-nasil-bir-araya-gelir\/\">Automating DNS and VPS provisioning with Terraform and Cloudflare<\/a><br \/>\n<a href=\"https:\/\/www.dchost.com\/blog\/en\/bulutun-ilk-nefesi-cloud%E2%80%91init-ve-ansible-ile-tekrar-uretilebilir-vps-nasil-kurulur\/\">From blank VPS to ready\u2011to\u2011serve with cloud\u2011init and Ansible<\/a><br \/>\n<a href=\"https:\/\/www.dchost.com\/blog\/en\/yonetim-panellerini-mtls-ile-nasil-kale-gibi-korursun-nginxte-istemci-sertifikalari-adim-adim\/\">Protecting admin panels with mTLS on Nginx<\/a><br \/>\n<a href=\"https:\/\/www.dchost.com\/blog\/en\/dv-ov-ev-ve-wildcard-ssl-arasinda-kaybolmadan-e%E2%80%91ticaret-ve-saaste-hangi-sertifika-ne-zaman\/\">Choosing the right certificate type without the drama<\/a><\/p>\n<\/div>","protected":false},"excerpt":{"rendered":"<p>So there I was, staring at a flood of logs on a late Tuesday evening, realizing I had built myself a perfectly functioning email server that nobody trusted yet. The messages were queued neatly, signed with DKIM, the SPF was crisp, DMARC was ready for inspection. But those first few emails still tiptoed into promotion [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":1714,"comment_status":"","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[26],"tags":[],"class_list":["post-1713","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-teknoloji"],"_links":{"self":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/1713","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/comments?post=1713"}],"version-history":[{"count":0,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/posts\/1713\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media\/1714"}],"wp:attachment":[{"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/media?parent=1713"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/categories?post=1713"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dchost.com\/blog\/en\/wp-json\/wp\/v2\/tags?post=1713"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}