Skip to main content

SMTP relay PaaS plugin for the Exordos MetaPaaS runtime (exim4)

Project description

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/

Project details


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.2.tar.gz (171.6 kB 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.2-py3-none-any.whl (40.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: exordos_mail-0.0.2.tar.gz
  • Upload date:
  • Size: 171.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for exordos_mail-0.0.2.tar.gz
Algorithm Hash digest
SHA256 856879ecc5ab6fb7bb8fad8ce9060db80d7117609637de38bdb4512afc94fa5f
MD5 ac351a2a21174975519506d6d394f622
BLAKE2b-256 21317b57b5de79847125b5059ee0b9875914ce13e7bfdd159e4129ffed6b6885

See more details on using hashes here.

Provenance

The following attestation bundles were made for exordos_mail-0.0.2.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.2-py3-none-any.whl.

File metadata

  • Download URL: exordos_mail-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 40.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for exordos_mail-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 e72f385efe6de0bc44cbda826d8e4181b8a592c6407f2904882d280d92129a09
MD5 3b9298db710d3441abe879fa7110aff0
BLAKE2b-256 1274e56dc5dcbee49e1fa403830ced674043b5130505569382ac18d654e4370f

See more details on using hashes here.

Provenance

The following attestation bundles were made for exordos_mail-0.0.2-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.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page