tractatus/docs/PROTONBRIDGE_SETUP.md
TheFlow 8b9f946a4a feat: Migrate from SendGrid to ProtonBridge for email sending
Complete migration to ProtonBridge following proven family-history architecture:

Backend Changes:
- Replace @sendgrid/mail with nodemailer
- Refactor EmailService for ProtonBridge/SMTP
- Add smart port detection (1026 prod, 1025 dev)
- Implement connection pooling and rate limiting
- Add EMAIL_ENABLED flag for dev/prod separation
- Add checkConnection() method for health checks

Email Service Features:
- Localhost-only SMTP (127.0.0.1)
- Automatic production/development port detection
- Connection verification on initialization
- Connection pooling (max 5 connections)
- Rate limiting (10 messages/second)
- Graceful fallback when email disabled

Documentation:
- Complete ProtonBridge setup guide (VPS installation)
- Quick start guide (30-minute setup)
- Systemd service file template
- Environment variable configuration
- Troubleshooting guide
- Migration notes from SendGrid

Architecture Benefits:
- Privacy-focused (end-to-end encrypted via Proton)
- Self-hosted bridge on VPS (no third-party API)
- Validated in production (family-history: 3+ months, 315+ restarts)
- Cost-effective (Proton paid account ~$4/month)
- No external dependencies (localhost SMTP)

Next Steps:
1. Install ProtonBridge on production VPS
2. Update production .env with Bridge credentials
3. Deploy email service changes
4. Test newsletter sending

See docs/PROTONBRIDGE_QUICKSTART.md for deployment guide

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-04 12:02:17 +13:00

13 KiB

ProtonBridge Email Setup for Tractatus

Overview

Tractatus uses ProtonBridge for email sending, replicating the proven architecture from the family-history project. ProtonBridge runs as a systemd service on the production VPS, providing localhost SMTP/IMAP access to your Proton account.

Status: Proven architecture (validated in family-history production: 3+ months uptime, 315+ app restarts, zero email disruptions as of 2025-11-03)


Architecture

┌─────────────────────────────────────────────────┐
│ Tractatus Application (Node.js)                 │
│ ├─ Email Service (Nodemailer)                   │
│ └─ Connects to: localhost:1026 (SMTP)          │
└─────────────────┬───────────────────────────────┘
                  │
                  │ TCP Connection
                  │
┌─────────────────▼───────────────────────────────┐
│ ProtonBridge (Systemd Service)                  │
│ ├─ Listens on: 127.0.0.1:1026 (prod)           │
│ ├─ Auth: Bridge-generated password              │
│ └─ Connects to: ProtonMail servers              │
└─────────────────┬───────────────────────────────┘
                  │
                  │ TLS/HTTPS
                  │
┌─────────────────▼───────────────────────────────┐
│ ProtonMail Servers                              │
│ └─ Actual email delivery                        │
└─────────────────────────────────────────────────┘

Part 1: VPS Setup (One-time Configuration)

Prerequisites

  • Ubuntu 22.04 LTS VPS (already configured)
  • Paid Proton account
  • SSH access to production server: vps-93a693da.vps.ovh.net

Step 1: Install ProtonBridge on VPS

# SSH to production server
ssh -i ~/.ssh/tractatus_deploy ubuntu@vps-93a693da.vps.ovh.net

# Install dependencies
sudo apt-get update
sudo apt-get install -y pass gnupg xvfb

# Download ProtonBridge (check for latest version)
wget https://proton.me/download/bridge/protonmail-bridge_3.0.21-1_amd64.deb
sudo dpkg -i protonmail-bridge_3.0.21-1_amd64.deb
sudo apt-get install -f  # Fix any dependency issues

Step 2: Configure GPG and Pass

# Generate GPG key (for pass credential manager)
gpg --gen-key
# - Use real name and email
# - Choose strong passphrase
# - Save the key ID shown

# Initialize pass with your GPG key ID
pass init "YOUR_GPG_KEY_ID"

Step 3: Configure ProtonBridge

# Run ProtonBridge interactively (first time only)
protonmail-bridge --cli

# In ProtonBridge CLI:
> login
# Enter your Proton account credentials

> info
# IMPORTANT: Copy the Bridge password shown (different from Proton password)
# Example: cETwrBktTQMBQrMddzCFIg
# This is what SMTP_PASS will be

> exit

Step 4: Create ProtonBridge Systemd Service

Create service file:

sudo nano /etc/systemd/system/protonmail-bridge.service

Paste this configuration:

[Unit]
Description=ProtonMail Bridge
After=network.target

[Service]
Type=simple
User=ubuntu
WorkingDirectory=/home/ubuntu
Environment="PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
Environment="HOME=/home/ubuntu"
Environment="DISPLAY=:99"
Environment="DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus"
Environment="XDG_RUNTIME_DIR=/run/user/1000"
ExecStartPre=/bin/bash -c 'if ! pgrep -x "Xvfb" > /dev/null; then Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & fi'
ExecStart=/usr/bin/protonmail-bridge --noninteractive
Restart=always
RestartSec=10
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Enable and start the service:

# Reload systemd
sudo systemctl daemon-reload

# Enable for auto-start on boot
sudo systemctl enable protonmail-bridge

# Start the service
sudo systemctl start protonmail-bridge

# Check status
sudo systemctl status protonmail-bridge

# Should show: "active (running)"

Step 5: Verify ProtonBridge Ports

# Test SMTP port (should connect)
nc -zv 127.0.0.1 1026

# Test IMAP port (should connect)
nc -zv 127.0.0.1 1144

# View ProtonBridge logs
sudo journalctl -u protonmail-bridge -f

Part 2: Tractatus Application Configuration

Environment Variables (Production)

File: /var/www/tractatus/.env (on production server)

Add these variables:

# Email Service Configuration
EMAIL_ENABLED=true
EMAIL_PROVIDER=proton

# SMTP Configuration (ProtonBridge)
SMTP_HOST=127.0.0.1
SMTP_PORT=1026                        # Production port
SMTP_SECURE=false                     # localhost doesn't need TLS
SMTP_USER=your-tractatus-email@pm.me  # Your Proton email
SMTP_PASS=YOUR_BRIDGE_PASSWORD        # From ProtonBridge setup (Step 3)
EMAIL_FROM=your-tractatus-email@pm.me

# Newsletter URLs
NEWSLETTER_UNSUBSCRIBE_BASE_URL=https://agenticgovernance.digital/api/newsletter/unsubscribe
NEWSLETTER_PREFERENCES_BASE_URL=https://agenticgovernance.digital/newsletter/preferences

Environment Variables (Development)

File: /home/theflow/projects/tractatus/.env (local dev machine)

# Email Service Configuration (DISABLED in dev)
EMAIL_ENABLED=false

# Optional: If you want to test locally with ProtonBridge
# SMTP_HOST=127.0.0.1
# SMTP_PORT=1025                      # Development port
# SMTP_USER=your-email@pm.me
# SMTP_PASS=YOUR_BRIDGE_PASSWORD

Part 3: Production Deployment Script

The existing deploy.sh script will handle deployment. ProtonBridge configuration is managed via .env on the production server.

Manual Deployment Steps (if needed)

# From local machine
cd /home/theflow/projects/tractatus

# Deploy email service changes
./scripts/deploy.sh src/services/email.service.js --restart

# Or full deployment
./scripts/deploy.sh

Part 4: Testing & Verification

Test 1: Check ProtonBridge Status

# On production server
sudo systemctl status protonmail-bridge

# Should show:
# Active: active (running) since...
# Uptime: X days

Test 2: Test SMTP Connection

# On production server
telnet 127.0.0.1 1026

# Should connect successfully
# Type QUIT to exit

Test 3: Test Email Sending (Node.js)

# On production server
cd /var/www/tractatus

# Quick test script
node -e "
const nodemailer = require('nodemailer');
const transporter = nodemailer.createTransport({
  host: '127.0.0.1',
  port: 1026,
  secure: false,
  auth: {
    user: 'your-email@pm.me',
    pass: 'YOUR_BRIDGE_PASSWORD'
  },
  tls: { rejectUnauthorized: false }
});

transporter.sendMail({
  from: 'your-email@pm.me',
  to: 'test@example.com',
  subject: 'ProtonBridge Test',
  text: 'Test email from Tractatus'
}, (err, info) => {
  if (err) {
    console.error('Error:', err);
  } else {
    console.log('Success! Message ID:', info.messageId);
  }
  process.exit(err ? 1 : 0);
});
"

Test 4: Check Application Health

# Test health endpoint
curl -s https://agenticgovernance.digital/health/detailed | jq '.services.email'

# Should show:
# {
#   "status": "running",
#   "smtp": {
#     "status": "connected",
#     "host": "127.0.0.1",
#     "port": "1026"
#   }
# }

Test 5: Send Test Newsletter

  1. Access newsletter administration interface (admin authentication required)
  2. Fill in newsletter form (use JSON for content)
  3. Click "Send Test" button
  4. Enter your email address
  5. Check inbox for test email

Monitoring & Maintenance

View ProtonBridge Logs

# Real-time logs
sudo journalctl -u protonmail-bridge -f

# Last 50 lines
sudo journalctl -u protonmail-bridge -n 50

# Logs from specific date
sudo journalctl -u protonmail-bridge --since "2025-11-03"

View Application Email Logs

# Tractatus uses systemd service
sudo journalctl -u tractatus -f | grep EmailService

# Or check PM2 logs (if using PM2)
pm2 logs tractatus-prod | grep EmailService

Restart Services

# Restart ProtonBridge (rarely needed)
sudo systemctl restart protonmail-bridge

# Restart Tractatus application
sudo systemctl restart tractatus

Health Check Commands

# Check ProtonBridge is listening
ss -tuln | grep -E '1026|1144'

# Check application connection
curl -s http://localhost:9000/health/detailed | jq .

# Test SMTP auth
nc -zv 127.0.0.1 1026

Troubleshooting

Problem: "SMTP connection verification failed"

Cause: ProtonBridge not running or not fully synced

Solution:

# Check ProtonBridge status
sudo systemctl status protonmail-bridge

# Check if ports are listening
ss -tuln | grep 1026

# Restart ProtonBridge
sudo systemctl restart protonmail-bridge

# Wait 30 seconds for mailbox sync
sleep 30

# Restart application
sudo systemctl restart tractatus

Problem: "Authentication failed"

Cause: Incorrect Bridge password (not Proton account password)

Solution:

# Get correct Bridge password
protonmail-bridge --cli
> info
> exit

# Update .env with correct SMTP_PASS
nano /var/www/tractatus/.env

# Restart application
sudo systemctl restart tractatus

Problem: Email sending works but emails not received

Cause: SPF/DKIM records not configured

Solution: ProtonMail handles SPF/DKIM automatically - no DNS changes needed. Check spam folder.

Problem: ProtonBridge keeps restarting

Cause: GPG/pass configuration issue

Solution:

# Check GPG keys
gpg --list-keys

# Reinitialize pass if needed
pass init "YOUR_GPG_KEY_ID"

# Reconfigure ProtonBridge
protonmail-bridge --cli
> login
> info
> exit

Port Reference

Service Environment Port Protocol
ProtonBridge SMTP Production 1026 STARTTLS
ProtonBridge SMTP Development 1025 STARTTLS
ProtonBridge IMAP Production 1144 STARTTLS
ProtonBridge IMAP Development 1143 STARTTLS

Note: Tractatus EmailService automatically detects production vs development and uses the correct port.


Security Considerations

  1. Localhost Only: ProtonBridge only binds to 127.0.0.1 - not accessible externally
  2. No TLS Needed: Localhost connections are secure without TLS
  3. Bridge Password: Different from Proton account credentials (generated by ProtonBridge)
  4. Email Disabled in Dev: Prevents accidental email sends during development
  5. Rate Limiting: EmailService enforces 10 emails/second max
  6. Connection Pooling: Reuses connections for efficiency

Comparison: ProtonBridge vs SendGrid

Feature ProtonBridge SendGrid
Cost Paid Proton account (~$4/month) Free: 100/day, Paid: $19.95/month
Privacy End-to-end encrypted Third-party data access
Deliverability Good (uses Proton infrastructure) Excellent (dedicated IPs, reputation)
Setup Complexity Moderate (requires VPS setup) Easy (API key only)
Sending Limits 1,000/day (Proton paid) 50,000/month (paid tier)
Control Self-hosted bridge Cloud service
Reliability Depends on VPS uptime 99.9% SLA

Migration from SendGrid

Already completed! The changes include:

  1. Replaced @sendgrid/mail with nodemailer
  2. Updated EmailService with ProtonBridge configuration
  3. Added smart port detection (prod vs dev)
  4. Implemented connection pooling and rate limiting
  5. Added EMAIL_ENABLED flag for dev/prod separation

No API changes - existing newsletter functionality works identically.


Next Steps

  1. Install ProtonBridge on production server (Part 1)
  2. Update production .env with Bridge credentials (Part 2)
  3. Deploy updated EmailService (Part 3)
  4. Test email sending (Part 4)
  5. Monitor for 24 hours to ensure stability

Support & Resources


Last Updated: 2025-11-03 Architecture Version: 1.0 (based on family-history production setup)