# Migadu Email Infrastructure — Add Domain & Alias Guide

# Migadu Email Infrastructure — Alias &amp; Mailbox Management

**MC #100300 — 2026-05-10 | Owner: FlowForge (kelsey-hightower)**

**Replaces:** CF Email Routing alias pattern. Migadu Mini ($90/yr) is now canonical for all ALAI email.

## Account &amp; API

- **Migadu account:** alem@alai.no (admin)
- **API base URL:** https://api.migadu.com/v1/
- **Auth:** HTTP Basic — username=alem@alai.no, password=API token (BW item: 78a41da0-b36f-46b9-b6e2-509b39768cec)
- **IMAP:** imap.migadu.com:993 (SSL)
- **SMTP:** smtp.migadu.com:465 (SSL)

## Registered Domains (7)

alai.no | bilko.io | bilko.cloud | bilko.company | basicconsulting.no | basicfakta.no | getdrop.no

## Active Mailboxes (5)

<table id="bkmrk-addressbw-item-namep"><thead><tr><th>Address</th><th>BW Item Name</th><th>Purpose</th></tr></thead><tbody><tr><td>alem@alai.no</td><td>Migadu — alem@alai.no</td><td>CEO primary inbox</td></tr><tr><td>sales@bilko.io</td><td>Migadu — sales@bilko.io</td><td>Bilko SR sales/lead</td></tr><tr><td>sales@bilko.cloud</td><td>Migadu — sales@bilko.cloud</td><td>Bilko HR sales/lead</td></tr><tr><td>sales@bilko.company</td><td>Migadu — sales@bilko.company</td><td>Bilko BA sales/lead</td></tr><tr><td>privacy@bilko.io</td><td>Migadu — privacy@bilko.io</td><td>Bilko privacy requests</td></tr></tbody></table>

## How to Add a New Alias

An alias delivers to an existing mailbox without creating a new inbox.

```bash
# 1. Get Migadu token from Bitwarden
BW_SESSION=$(cat /tmp/bw-session)
TOKEN=$(bw get password "78a41da0-b36f-46b9-b6e2-509b39768cec" --session "$BW_SESSION")

# 2. Create forwarding (alias) on an existing mailbox
# This adds contact@bilko.io -> delivered to sales@bilko.io mailbox
curl -X POST "https://api.migadu.com/v1/domains/bilko.io/mailboxes/sales/forwardings/" \
  -u "alem@alai.no:${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"address":"contact@bilko.io","name":"Contact Alias"}'

# 3. Verify
curl -s "https://api.migadu.com/v1/domains/bilko.io/mailboxes/sales" \
  -u "alem@alai.no:${TOKEN}" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('forwardings', []))"
```

## How to Add a New Mailbox

```bash
TOKEN=$(bw get password "78a41da0-b36f-46b9-b6e2-509b39768cec" --session "$(cat /tmp/bw-session)")

# Create new mailbox
curl -X POST "https://api.migadu.com/v1/domains/alai.no/mailboxes/" \
  -u "alem@alai.no:${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"local_part":"hr","name":"HR Team","password":"<strong_password>","password_recovery_email":"alem@alai.no"}'

# Save password to Bitwarden immediately
echo '{"object":"item","type":1,"name":"Migadu — hr@alai.no","notes":"IMAP: imap.migadu.com:993 | SMTP: smtp.migadu.com:465","login":{"username":"hr@alai.no","password":"<strong_password>","uris":[]}}' | \
  bw encode | bw create item --session "$(cat /tmp/bw-session)"</strong_password></strong_password>
```

## How to Add a New Domain

```bash
TOKEN=$(bw get password "78a41da0-b36f-46b9-b6e2-509b39768cec" --session "$(cat /tmp/bw-session)")

# 1. Register domain
curl -X POST "https://api.migadu.com/v1/domains/" \
  -u "alem@alai.no:${TOKEN}" \
  -H "Content-Type: application/json" \
  -d '{"name":"newdomain.com"}'

# 2. Add DNS via CF (replace ZONE_ID):
CF_EMAIL="john@basicconsulting.no"
CF_KEY=$(bw get password "Cloudflare Global API Key" --session "$(cat /tmp/bw-session)")
ZONE_ID="<cf_zone_id>"
DOMAIN="newdomain.com"

# MX records
curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
  -H "X-Auth-Email: ${CF_EMAIL}" -H "X-Auth-Key: ${CF_KEY}" -H "Content-Type: application/json" \
  -d "{\"type\":\"MX\",\"name\":\"${DOMAIN}\",\"content\":\"aspmx1.migadu.com\",\"priority\":10,\"ttl\":300}"
curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
  -H "X-Auth-Email: ${CF_EMAIL}" -H "X-Auth-Key: ${CF_KEY}" -H "Content-Type: application/json" \
  -d "{\"type\":\"MX\",\"name\":\"${DOMAIN}\",\"content\":\"aspmx2.migadu.com\",\"priority\":20,\"ttl\":300}"

# SPF
curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
  -H "X-Auth-Email: ${CF_EMAIL}" -H "X-Auth-Key: ${CF_KEY}" -H "Content-Type: application/json" \
  -d "{\"type\":\"TXT\",\"name\":\"${DOMAIN}\",\"content\":\"v=spf1 include:spf.migadu.com ~all\",\"ttl\":300}"

# DMARC
curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
  -H "X-Auth-Email: ${CF_EMAIL}" -H "X-Auth-Key: ${CF_KEY}" -H "Content-Type: application/json" \
  -d "{\"type\":\"TXT\",\"name\":\"_dmarc.${DOMAIN}\",\"content\":\"v=DMARC1; p=none; rua=mailto:postmaster@${DOMAIN}\",\"ttl\":300}"

# DKIM CNAMEs (x3)
for key in key1 key2 key3; do
  curl -X POST "https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records" \
    -H "X-Auth-Email: ${CF_EMAIL}" -H "X-Auth-Key: ${CF_KEY}" -H "Content-Type: application/json" \
    -d "{\"type\":\"CNAME\",\"name\":\"${key}._domainkey.${DOMAIN}\",\"content\":\"${key}.${DOMAIN}._domainkey.migadu.com\",\"ttl\":300}"
done

# 3. Poll until verified (typically 30-120 min)
watch -n 60 "curl -s https://api.migadu.com/v1/domains/${DOMAIN} -u alem@alai.no:\${TOKEN} | python3 -c \"import sys,json; d=json.load(sys.stdin); print(d.get('can_receive'))\"" </cf_zone_id>
```

## Check Domain Verification

```bash
TOKEN=$(bw get password "78a41da0-b36f-46b9-b6e2-509b39768cec" --session "$(cat /tmp/bw-session)")

# All domains
curl -s "https://api.migadu.com/v1/domains/" -u "alem@alai.no:${TOKEN}" | \
  python3 -c "import sys,json; [print(f\"{d['name']}: state={d['state']}, can_receive={d['can_receive']}\") for d in json.load(sys.stdin)[\domains']]"
```

## CF Email Routing (DISABLED)

CF Email Routing has been **disabled** on bilko.io, bilko.cloud, bilko.company (2026-05-10). Do NOT re-enable. MX is now Migadu. Old routing rules are inactive.

## IMAP History Migration (imapsync)

Script: `/Users/makinja/business/ALAI-Holding-AS/infrastructure/email-migadu-migration.sh`

Run after all domains show `can_receive=True`. Source: imap.one.com:993 | 876 messages baseline (2026-05-10).

## one.com Cancellation (CEO action)

1. Confirm all Migadu domains active + 48h dual-host complete (2026-05-12T20:39Z)
2. Remove one.com MX records from CF zones: alai.no (id: 2d2028ebbe8fe433390a894111f56016) + basicconsulting.no (ids: 6b5c01115411ed28165fe294141c17bc, e5f35554bf4976bc6d5a85d4a309ff05, ce32445b537e1fbfc9c1f7cc9f051092, 614c98d0c34862cb28a8b9eb48b29823)
3. CEO logs into one.com -&gt; My Products -&gt; Cancel Email subscription