Skip to content

Postfix Mail Relay

hub2 runs Postfix as the central mail relay for all CharlieHub services. Emails are relayed through SendGrid for improved deliverability.

Overview

Property Value
Host hub2 (51.68.235.106)
Service Postfix 3.8.x
Relay SendGrid SMTP
Domain microshare.eu
PTR Record mail.microshare.eu

Configuration Date

SendGrid relay configured on 2026-01-07, replacing direct SMTP sending which had deliverability issues with Microsoft 365.

Architecture

┌─────────────────┐     ┌─────────────┐     ┌──────────────┐
│  CharlieHub     │     │   hub1      │     │   SendGrid   │
│  Services       │────▶│   Postfix   │────▶│   SMTP       │────▶ Recipients
│  (CT1935, etc)  │     │  + OpenDKIM │     │   Relay      │
└─────────────────┘     └─────────────┘     └──────────────┘

Email Authentication

All authentication mechanisms are configured and verified:

SPF Record

microshare.eu TXT "v=spf1 include:sendgrid.net include:_spf.google.com ip4:151.80.58.99 ~all"

DKIM (via SendGrid)

SendGrid signs outbound emails with DKIM. DNS records:

Record Type Value
s1._domainkey.microshare.eu CNAME s1.domainkey.u58662085.wl086.sendgrid.net
s2._domainkey.microshare.eu CNAME s2.domainkey.u58662085.wl086.sendgrid.net
em6444.microshare.eu CNAME u58662085.wl086.sendgrid.net

DMARC Record

_dmarc.microshare.eu TXT "v=DMARC1; p=quarantine; rua=mailto:cpaumelle@microshare.io; ruf=mailto:cpaumelle@microshare.io; fo=1"

Policy Active

DMARC policy set to quarantine - emails failing authentication will be sent to spam.

PTR (Reverse DNS)

IP Version Address PTR Record
IPv4 151.80.58.99 mail.microshare.eu
IPv6 2001:41d0:305:2100::3f7e mail.microshare.eu

Both configured via OVH API (see Credentials section).

Forward DNS (mail.microshare.eu)

Type Value
A 151.80.58.99
AAAA 2001:41d0:305:2100::3f7e

SendGrid Configuration

Domain Authentication

  • SendGrid domain ID: 29103814
  • Domain: microshare.eu
  • Status: Verified

Postfix Relay Configuration

Key settings in /etc/postfix/main.cf:

relayhost = [smtp.sendgrid.net]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
smtp_tls_security_level = encrypt
header_size_limit = 4096000

SASL Credentials

File /etc/postfix/sasl_passwd:

[smtp.sendgrid.net]:587 apikey:$SENDGRID_API_KEY

Credential Location

The SendGrid API key is stored in /root/.env on hub1. See Credentials section below.

Credentials

All email-related credentials are stored in /root/.env on hub2:

# SendGrid API (for SMTP relay)
SENDGRID_API_KEY=SG.xxxxx...

# OVH API for DNS management (microshare.eu)
# Used by Domain Manager for DNS records
OVH_APP_KEY=ef8d1c1f7bdc8f06
OVH_APP_SECRET=REDACTED_OVH_SECRET
OVH_CONSUMER_KEY=3c2a1fab3ccf695990fddb14632f2dbb

# OVH API for IP/PTR management (151.80.58.99)
# Separate credentials with IP management permissions
OVH_IP_APP_KEY=92fe9be8de50865b
OVH_IP_APP_SECRET=fa1815ee5c8b1feb4aa4b80a1497c275
OVH_IP_CONSUMER_KEY=47261cda3c536478b6acbf27e8811f72

Two OVH API Credentials

There are two sets of OVH API credentials:

  1. DNS credentials (OVH_APP_*): Used by Domain Manager for DNS record management
  2. IP credentials (OVH_IP_*): Used for PTR/reverse DNS management on the dedicated server IP

Sending Email

From hub1 directly

# Simple test
echo "Test message" | mail -s "Test Subject" -r "notifications@microshare.eu" recipient@example.com

# With proper From header
echo "Test message" | mail -s "Test Subject" \
  -r "notifications@microshare.eu" \
  -a "From: Service Name <notifications@microshare.eu>" \
  recipient@example.com

From other services

Services should connect to hub2 postfix on port 25 via WireGuard:

import smtplib
from email.mime.text import MIMEText

msg = MIMEText("Hello from CharlieHub")
msg["Subject"] = "Notification"
msg["From"] = "notifications@microshare.eu"
msg["To"] = "recipient@example.com"

# Use hub2's WireGuard IP for your site
with smtplib.SMTP("REDACTED_IP", 25) as server:  # hub2 WireGuard IP (UK)
    server.send_message(msg)

Envelope Sender

Always set envelope sender

When sending programmatically, always set the envelope sender (MAIL FROM) to match the From header domain. Mismatches can cause delivery issues or silent drops.

Monitoring

Check mail queue

mailq

View mail logs

tail -f /var/log/mail.log

Check SendGrid stats

source /root/.env
curl -s "https://api.sendgrid.com/v3/stats?start_date=$(date +%Y-%m-%d)" \
  -H "Authorization: Bearer $SENDGRID_API_KEY" | jq .

Check SendGrid suppression lists

source /root/.env

# Bounces
curl -s "https://api.sendgrid.com/v3/suppression/bounces" \
  -H "Authorization: Bearer $SENDGRID_API_KEY" | jq .

# Blocks
curl -s "https://api.sendgrid.com/v3/suppression/blocks" \
  -H "Authorization: Bearer $SENDGRID_API_KEY" | jq .

# Spam reports
curl -s "https://api.sendgrid.com/v3/suppression/spam_reports" \
  -H "Authorization: Bearer $SENDGRID_API_KEY" | jq .

Troubleshooting

Email not delivered

  1. Check mail log:

    grep "message-id" /var/log/mail.log | tail -20
    

  2. Check SendGrid accepted it: Look for status=sent and relay=smtp.sendgrid.net in logs

  3. Check SendGrid suppression lists: Recipient may be bounced/blocked

  4. Check recipient spam folder: Even with SendGrid, new senders may land in spam initially

SendGrid authentication error

550 The from address does not match a verified Sender Identity

Solution: Ensure domain authentication is complete in SendGrid:

source /root/.env
curl -s "https://api.sendgrid.com/v3/whitelabel/domains" \
  -H "Authorization: Bearer $SENDGRID_API_KEY" | jq ".[] | {id, domain, valid}"

Microsoft 365 marking as spam

M365 may still mark emails as spam (SCL:5) even with proper authentication. Solutions:

  1. Recipient adds Safe Sender: In Outlook settings, add microshare.eu
  2. M365 Admin creates transport rule: Bypass spam filtering for microshare.eu
  3. Time: Sender reputation builds over weeks of consistent legitimate sending

Postfix not relaying

# Check postfix status
systemctl status postfix

# Test SMTP connection to SendGrid
openssl s_client -connect smtp.sendgrid.net:587 -starttls smtp

# Verify SASL credentials
postmap -q "[smtp.sendgrid.net]:587" /etc/postfix/sasl_passwd

Services Using Email

Service Purpose From Address
CT1935 (pescle-rodent) Video notifications notifications@microshare.eu
Domain Manager Alert notifications notifications@microshare.eu

DNS Management

Add/Update DNS records via OVH API

import ovh

client = ovh.Client(
    endpoint="ovh-eu",
    application_key="ef8d1c1f7bdc8f06",
    application_secret="REDACTED_OVH_SECRET",
    consumer_key="3c2a1fab3ccf695990fddb14632f2dbb"
)

# Add TXT record
client.post("/domain/zone/microshare.eu/record",
    fieldType="TXT",
    subDomain="_dmarc",
    target='"v=DMARC1; p=quarantine"',
    ttl=3600
)

# Refresh zone
client.post("/domain/zone/microshare.eu/refresh")

Update PTR record via OVH API

import ovh

client = ovh.Client(
    endpoint="ovh-eu",
    application_key="92fe9be8de50865b",
    application_secret="fa1815ee5c8b1feb4aa4b80a1497c275",
    consumer_key="47261cda3c536478b6acbf27e8811f72"
)

# Update IPv4 reverse DNS
client.put("/ip/151.80.58.99/reverse/151.80.58.99",
    reverse="mail.microshare.eu"
)

# Update IPv6 reverse DNS (delete and recreate)
ipv6 = "2001:41d0:305:2100::3f7e"
client.delete(f"/ip/{ipv6}/reverse/{ipv6}")
client.post(f"/ip/{ipv6}/reverse",
    ipReverse=ipv6,
    reverse="mail.microshare.eu"
)

History

Date Change
2026-01-08 Upgraded DMARC policy from p=none to p=quarantine
2026-01-07 Configured SendGrid relay, domain authentication
2026-01-07 Added DKIM via SendGrid (s1, s2 selectors)
2026-01-07 Added DMARC policy (p=none with reporting)
2026-01-07 Configured IPv4 PTR record (mail.microshare.eu)
2026-01-07 Configured IPv6 PTR record (mail.microshare.eu)
2026-01-07 Added AAAA record for mail.microshare.eu
2026-01-07 Stored all credentials in /root/.env on hub1