mailnix / Soft sandbox

    Core concepts

    Soft sandbox

    mailnix decides relay-vs-capture from three signals, never from the recipient domain. The legacy @sandbox.mailnix.ch rule is gone.

    Three signals

    1. Project status. Anonymous projects always capture, regardless of recipient.
    2. Destination mode. A destination with mode = 'sandbox' captures; 'live' relays. New destinations default to sandbox; the explicit destination_promote_to_live mutation flips them. Existing destinations were backfilled to live by Migration 081.
    3. No-route policy. When no destination matches, the project's no_route_policy decides: capture (default for new projects), reject (default for existing), or relay_default (currently behaves like reject).

    The outcome field

    Every trace.Send response (REST + MCP) carries an outcome field:

    • relayed: sent to a real provider.
    • captured.anonymous_project
    • captured.sandbox_destination
    • captured.no_route

    Each captured row records:

    • capture_reason: one of the three above.
    • destination_id: which destination would have handled the relay (null for anonymous + no_route).
    • intended_to / intended_from: recipient + sender as requested.
    • addresses_seen: every email extracted from headers + body, GIN-indexed, powering cross-recipient search.

    Anonymous projects can send anywhere

    Anonymous projects send to any recipient. The capture happens because the project is anonymous, not because the recipient sits on a special domain. The MCP email_send_test tool description spells this out for AI clients.

    Capture cap

    Each project has a monthly_capture_cap (free tier = 5,000). Sends past the cap return HTTP 402 with error.code = "quota_exhausted_captures". The counter rolls inline at the month boundary; no cron required.

    Full reference

    The complete contract lives in the public reference at SOFT_SANDBOX.md.