153 lines
8.1 KiB
Markdown
153 lines
8.1 KiB
Markdown
# Campaign and Mail Profile Boundary
|
|
|
|
## Product view
|
|
|
|
A campaign chooses an authorized Mail profile. It does not define a mail
|
|
server. The Campaign module owns recipients, content, attachment rules,
|
|
delivery intent, review state, and delivery evidence. The Mail module owns the
|
|
SMTP/IMAP endpoints, encrypted credentials, connection tests, profile policy,
|
|
and runtime transport adapters.
|
|
|
|
The persisted campaign contract is therefore deliberately narrow:
|
|
|
|
```json
|
|
{
|
|
"server": {
|
|
"mail_profile_id": "stable-mail-profile-id"
|
|
}
|
|
}
|
|
```
|
|
|
|
No `server.smtp`, `server.imap`, `server.credentials`, credential-inheritance
|
|
override, or password is valid campaign JSON.
|
|
|
|
## User journey
|
|
|
|
1. A Mail administrator creates and tests a reusable profile in Mail.
|
|
2. A campaign author opens **Mail settings** and selects one profile available
|
|
for the campaign's tenant, owner, and policy context.
|
|
3. Campaign stores only the stable profile identifier.
|
|
4. Validation asks Mail to authorize the active profile and returns only
|
|
availability flags plus opaque Mail-owned transport revisions. Reading that
|
|
summary does not decrypt credentials.
|
|
5. Build stores the profile identifier, delivery policy, job manifest, and
|
|
non-secret transport revisions as execution evidence. It stores no
|
|
resolved host, username, password, or other transport material.
|
|
6. A delivery worker invokes one Mail-owned effect operation. Mail re-authorizes
|
|
the profile, resolves credentials, compares the expected transport
|
|
revision, checks policy, and sends or appends without returning transport
|
|
material to Campaign. If the selected profile or its non-secret transport settings
|
|
changed after build, delivery stops until the campaign is revalidated and
|
|
rebuilt. A password rotation that leaves the transport identity unchanged
|
|
does not invalidate the build.
|
|
7. Mail returns only Campaign-owned envelope addresses, counts, sanitized
|
|
refusal classifications/status codes, or the selected Sent folder. Raw
|
|
server banners, provider bytes, host details, and credentials never enter
|
|
Campaign attempts or public evidence.
|
|
|
|
Non-dry Campaign report email currently fails closed. It must not bypass the
|
|
durable job/effect model through a direct SMTP call. Re-enabling it requires the
|
|
Mail-owned idempotent outbox, attempt, unknown-outcome, and reconciliation path
|
|
tracked in
|
|
[`govoplan-mail#17`](https://git.add-ideas.de/GovOPlaN/govoplan-mail/issues/17).
|
|
Report generation and dry-run validation remain separate from an external
|
|
effect; recipient-level exports require recipient-export authorization.
|
|
|
|
Campaign authors need `mail:profile:use` in addition to the relevant Campaign
|
|
permission. Profile visibility remains governed by Mail policy and campaign
|
|
owner context.
|
|
|
|
## Existing database rows and migration
|
|
|
|
The current database can contain campaign versions with inline SMTP/IMAP
|
|
settings or credentials. There is no separate historical Campaign JSON corpus
|
|
to import or remediate. GovOPlaN treats those inline fields as inert legacy
|
|
material and does not delete or rewrite the stored audit rows automatically:
|
|
|
|
- API responses omit all legacy transport fields and secrets and expose a
|
|
`mail_profile_migration_required` marker.
|
|
- validation, build, queue, retry, and delivery fail closed with an actionable
|
|
profile-migration error;
|
|
- unrelated edits preserve the exact stored legacy server object when the
|
|
submitted public Mail references are unchanged; they cannot silently scrub,
|
|
edit, or re-submit legacy fields or credentials;
|
|
- an editable version is migrated only through an explicit Mail-settings save
|
|
with an authorized profile; and
|
|
- a locked version remains unchanged. Creating its editable successor records
|
|
the migration while retaining the locked source as audit evidence.
|
|
|
|
Legacy execution snapshots are likewise retained but cannot be used for
|
|
delivery. Revalidate and rebuild an editable profile-only version. Normal
|
|
database backup, restore, encryption, and access controls apply to the current
|
|
database as a whole; the product does not define a separate historical-JSON or
|
|
inline-secret recovery workflow. A restored legacy row remains inert and
|
|
fail-closed under the same rules.
|
|
|
|
### Migrate from the Campaign UI
|
|
|
|
Open **Mail settings** from the migration notice for the selected version.
|
|
Select an authorized Mail profile and choose **Migrate selected Mail profile**.
|
|
The migration action is available even when that profile was already selected
|
|
and the draft has no other unsaved changes. If the version is locked, first use
|
|
its supported unlock or editable-successor action; protected source evidence is
|
|
not rewritten. Reopen the settings and confirm that the migration notice has
|
|
gone, then validate, build, and review before separately authorizing delivery.
|
|
Migration itself never sends mail.
|
|
|
|
Mail migration and ZIP policy repairs can be saved in either order. An exact,
|
|
unchanged ZIP configuration does not require a new acknowledgement merely to
|
|
save a Mail migration, even if the existing ZIP policy or actor's permission is
|
|
no longer valid. No actor, timestamp, or consent is invented. Any ZIP change
|
|
still requires the complete current archive policy and, for ZipCrypto, the
|
|
dedicated permission and reasoned acknowledgement. Conversely, saving an
|
|
archive correction with unchanged public Mail references retains the exact
|
|
legacy transport server-side, without using or reauthorizing the old profile.
|
|
The migration notice remains until the explicit authorized migration succeeds.
|
|
Changing any Mail profile, server, or credential reference is not an unrelated
|
|
repair. Inline transport is rejected even if a caller echoes stored values.
|
|
The same edit-time separation applies after migration: retaining an unchanged
|
|
Mail selection does not invoke use-policy while saving an unrelated correction,
|
|
even if a later policy requires an explicit credential. Selecting a new resource
|
|
or explicitly migrating still checks Mail permission and current policy; actual
|
|
validation and delivery always recheck them, regardless of save history.
|
|
Both repair orders invalidate build/execution evidence; validation, build,
|
|
review and delivery remain blocked until all outstanding conditions are valid.
|
|
|
|
Successful saves and subsequent refreshes are separate outcomes. A committed
|
|
save is not undone by a failed workspace refresh. The workspace retains its
|
|
last usable same-campaign/version data and displays the refresh error; retry
|
|
Reload to fetch the current server state. Obsolete responses from an earlier
|
|
campaign, version, signed-in identity, or reload cannot replace newer data.
|
|
|
|
The normal profile selector requests only campaign-authorized profiles. The
|
|
administrative profile catalogue is requested separately on **Mail policy**;
|
|
failure or lack of authority there does not empty the usable profile selector.
|
|
Profile-list errors remain visible next to the affected settings.
|
|
|
|
While migration is required, **Review and send** remains read-only and links to
|
|
the exact version's Mail settings. It does not repeatedly attempt incompatible
|
|
attachment-preview requests. These UI affordances do not relax backend
|
|
validation, build, queue, retry, or delivery enforcement.
|
|
|
|
### Editor metadata and trusted evidence
|
|
|
|
Read responses may contain server-owned `review_send` and `approval_gate`
|
|
evidence. Ordinary version mutations send only client-owned `created_from`,
|
|
`field_overrides`, and `opt_ins` editor metadata. The client omits review and
|
|
approval evidence; the server rejects attempts to write it through an editor
|
|
mutation and preserves its existing trusted value during metadata updates.
|
|
Supported unlock, successor-version, and build invalidation rules still remove
|
|
stale evidence when required. Opening or leaving the Template editor must not
|
|
require manually deleting server review metadata.
|
|
|
|
## Operator checks
|
|
|
|
Before live delivery, confirm that:
|
|
|
|
- the profile is active and still authorized for the campaign owner;
|
|
- SMTP and optional IMAP profile tests pass;
|
|
- validation and build occurred after the latest transport-identity change;
|
|
- append-to-Sent is enabled only when the selected profile has IMAP; and
|
|
- reports show the profile-bound snapshot revisions and delivery outcomes,
|
|
never credentials or resolved transport configuration.
|