Skip to main content

mailaas: SMTP Relay PaaS Plugin for MetaPaaS

exim4 SMTP submission server packaged as a MetaPaaS plugin, following the same pattern as metapaas_s3.

Architecture

metapaas-cp
└── mail plugin (exordos_paas_mail)
    ├── CP: MailInstance + MailAccount models, REST API, migrations
    ├── infra_builder: CoreInfraBuilder → NodeSet + Config on core
    └── paas_builder: MailInstanceBuilder → MailInstanceNode → DP agent

mailaas-dp-<uuid> (VM)
└── exim4 (SMTP 25/465/587 — STARTTLS + auth)
    ├── /etc/exordos_metapaas/mail.env  ← delivered by CP (MAIL_DOMAIN)
    ├── /etc/exim4/passwd               ← managed by DP agent (lsearch auth)
    └── exordos-universal-agent         ← MailCapabilityDriver

Quick Start

Build

make build \
  REPOSITORY=http://10.20.0.1:8080/exordos-elements \
  INDEX_URL=http://10.20.0.1:8080/simple/

Produces:

  • output/images/exordos-metapaas-mail-dp.raw.zst (DP image)
  • output/manifests/mailaas.yaml (element manifest)

Install on running metapaas

make install

PluginReconciler on metapaas-cp installs exordos_paas_mail via pip and activates the /v1/types/mail/ route.

Create Instance

curl -X POST http://metapaas-cp:8080/v1/types/mail/instances/ \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d '{
    "name": "mail-prod",
    "project_id": "4d657461-0000-0000-0000-000000000002",
    "domain": "example.com",
    "cpu": 2,
    "ram": 2048,
    "disk_size": 20,
    "version": "/v1/types/mail/versions/<version-uuid>"
  }'

Create SMTP Account

# Generate SHA512-crypt hash (compatible with exim4 crypteq)
HASH=$(openssl passwd -6 "mypassword")

curl -X POST http://metapaas-cp:8080/v1/types/mail/instances/<uuid>/accounts/ \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer <token>' \
  -d "{
    \"username\": \"alice\",
    \"password_hash\": \"${HASH}\",
    \"project_id\": \"4d657461-0000-0000-0000-000000000002\",
    \"instance\": \"/v1/types/mail/instances/<uuid>\"
  }"

Within seconds the DP agent writes the account to /etc/exim4/passwd and reloads exim4. The user can then authenticate via SMTP AUTH (PLAIN/LOGIN over STARTTLS on port 587 or SMTPS on port 465).

Hashes stored with a Dovecot {SHA512-CRYPT} scheme prefix are accepted — the driver strips the prefix before writing to exim4's passwd file.

Configure DNS

For mail to be accepted by other servers you must publish a few DNS records for your domain (referred to below as $1, e.g. example.com).

  • DKIM — the key is generated on the node by the configure script. Once the instance is ACTIVE, read it from the API:

    curl -s http://metapaas-cp:8080/v1/types/mail/instances/<uuid> \
      -H 'Authorization: Bearer <token>' | jq -r '{dkim_selector, dkim_public_key}'
    

    Publish it as a TXT record at <dkim_selector>._domainkey.$1 (default selector: platform), with the dkim_public_key value as data. The raw record is also on the node at /etc/exim4/dkim/platform.txt.

  • SPF — name: @ (the domain itself), type: TXT, TTL: 3600, data: "v=spf1 ip4:YOUR_SERVER_IP/32 a mx ~all"

  • DMARC — name: _dmarc, type: TXT, TTL: 3600, data: "v=DMARC1; p=none; pct=100; adkim=s; aspf=s"

  • PTR — set the reverse record for your server IP to $1

  • MX — ensure an MX record exists (e.g. name: @, type: MX, data: $1)

API Endpoints

Method Path Description
POST /v1/types/mail/instances/ Create mail server
GET /v1/types/mail/instances/ List instances
GET /v1/types/mail/instances/<uuid> Get instance
PATCH /v1/types/mail/instances/<uuid> Update (cpu/ram/disk_size)
DELETE /v1/types/mail/instances/<uuid> Delete
GET /v1/types/mail/versions/ List DP image versions
POST /v1/types/mail/instances/<uuid>/accounts/ Create account
GET /v1/types/mail/instances/<uuid>/accounts/ List accounts
PATCH /v1/types/mail/instances/<uuid>/accounts/<uuid> Update (active, password_hash)
DELETE /v1/types/mail/instances/<uuid>/accounts/<uuid> Delete account

Field permissions

Field Create Read Update
domain RW RO RO
status RO RO
ipsv4 RO RO
dkim_public_key RO RO
dkim_selector RO RO
password_hash RW hidden RW
username RW RO RO
active RW RW RW

Repository Layout

.
├── exordos_paas_mail/
│   ├── constants.py          # MAIL_ENV_FILE, EXIM4_PASSWD_FILE paths
│   ├── models.py             # MailVersion, MailInstance, MailAccount (restalchemy)
│   ├── controllers.py        # REST controllers (gcl_iam policy-based)
│   ├── routes.py             # Route tree (instances/accounts, versions)
│   ├── definition.py         # MailDefinition (PaaSDefinition contract)
│   ├── infra_models.py       # MailInstance + infra (NodeSet + Config)
│   ├── infra_builder.py      # CoreInfraBuilder (creates VMs + delivers mail.env)
│   ├── paas_models.py        # MailInstanceNode (target resource for DP agent)
│   ├── paas_builder.py       # MailInstanceBuilder (maps accounts → DP payload)
│   ├── driver.py             # MailCapabilityDriver: writes /etc/exim4/passwd
│   ├── utils.py              # remove_nested_dm helper
│   ├── migrations/
│   │   ├── 0000-init-mail.py # Creates mail_versions, mail_instances, mail_accounts
│   │   └── 0001-drop-root-password.py
│   └── tests/
│       ├── unit/             # Unit tests (models, driver)
│       └── functional/       # E2E tests (prepare_env.py + SMTP auth tests)
├── exordos/
│   ├── exordos.yaml          # Build config (deps + elements + DP image)
│   ├── images/
│   │   ├── dp_install.sh     # Packer: install exim4 + configure script + agent
│   │   └── dp_bootstrap.sh   # First-boot: persistent disk + start configure service
│   └── manifests/
│       ├── mailaas.yaml.j2  # Element manifest: type reg + IAM + DP version
│       └── example_mail.yaml.j2  # Example consumer element
├── etc/
│   ├── systemd/
│   │   ├── exordos-metapaas-mail-configure.service  # Configures exim4 from mail.env
│   │   └── exordos-metapaas-mail-agent.service      # Universal agent (MailCapabilityDriver)
│   └── exordos_metapaas/
│       ├── logging.yaml
│       └── metapaas_mail_agent.conf
├── .github/workflows/
│   ├── tests.yaml            # Lint (ruff) on every push
│   └── func_tests.yaml       # Full e2e: bootstrap core + deploy + SMTP tests
├── pyproject.toml
├── tox.ini
└── Makefile

Development

make test          # Unit tests via tox
make lint          # ruff check
make format        # ruff format
make typecheck     # mypy
make functional    # E2E tests (needs live stand)

Running functional tests manually

python exordos_paas_mail/tests/functional/prepare_env.py \
  --metapaas-dir ../exordos_metapaas \
  --project-dir . \
  --output-dir /tmp/mail-build \
  --endpoint http://10.20.0.2:11010 \
  --username admin --password <pass>

# Use env vars printed by prepare_env.py, then:
tox -e py312-functional

Key differences from metapaas_s3

Aspect s3aas mailaas
DP software RustFS exim4 (SMTP relay)
Instance children Bucket, Policy, User, AccessKey Account
Replicas 1–16 Always 1
Config delivered rustfs.env mail.env (domain only)
DP auth state S3 access keys /etc/exim4/passwd (SHA512-crypt)
On-change systemctl restart rustfs systemctl restart mail-configure
DP agent state file s3_meta.json mail_meta.json
uuid5 name s3aas mailaas

References

  • MetaPaaS design: ../exordos_metapaas/DESIGN.md
  • How to build new PaaS: ../exordos_s3/HOW_TO_BUILD_NEW_PAAS.md
  • Working reference: ../exordos_s3/

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

exordos_mail-0.0.7.tar.gz (1.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

exordos_mail-0.0.7-py3-none-any.whl (46.4 kB view details)

Uploaded Python 3

File details

Details for the file exordos_mail-0.0.7.tar.gz.

File metadata

  • Download URL: exordos_mail-0.0.7.tar.gz
  • Upload date:
  • Size: 1.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for exordos_mail-0.0.7.tar.gz
Algorithm Hash digest
SHA256 ebe1e0afd60d35170a20fab6ed85a23f426ecd94562caed8bccde03ac5f64dd9
MD5 b9481251f4bbe7874986c9e55ae3967d
BLAKE2b-256 6d0cd01c3f841b0f37de9281d02a5d8ec2275c534627c78fee46806ec06c60dd

See more details on using hashes here.

Provenance

The following attestation bundles were made for exordos_mail-0.0.7.tar.gz:

Publisher: publish-to-pypi.yml on exordos/exordos_mail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file exordos_mail-0.0.7-py3-none-any.whl.

File metadata

  • Download URL: exordos_mail-0.0.7-py3-none-any.whl
  • Upload date:
  • Size: 46.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for exordos_mail-0.0.7-py3-none-any.whl
Algorithm Hash digest
SHA256 ee9526524af63a61791e15c06a2c0969a128e2ff862dad8396e5531275c1c2cb
MD5 d045d5085c90659988e43131d97131fa
BLAKE2b-256 2c354c06a42a8bbcf3272448d0fc4882d9ea3fd27f929a4cdee64ca5276c8fdb

See more details on using hashes here.

Provenance

The following attestation bundles were made for exordos_mail-0.0.7-py3-none-any.whl:

Publisher: publish-to-pypi.yml on exordos/exordos_mail

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.0.8

2 files

This release

0.0.7 This release

2 files

0.0.6

2 files

0.0.5

2 files

0.0.4

2 files

0.0.3

2 files

0.0.2

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page