Reference
Mail Envelope And Result Reference
MailEnvelope is the normalized message object passed into a MailTransportInterface. MailDispatchResult is the stable success or failure object returned by a transport.
These objects are intentionally narrow. Provider transports can translate them into provider-specific payloads, but the source contract for extension authors is the object shape below.
Human Path
Extension authors read this page while implementing MailTransportInterface::send():
public function send(MailEnvelope $envelope): MailDispatchResult
{
if (!$this->isConfigured()) {
return MailDispatchResult::failed('x.my_vendor.api', 'mail_provider_not_configured');
}
return MailDispatchResult::ok('x.my_vendor.api', 'provider-message-id');
}
AI Path
An AI coding agent can use this reference while authoring a local transport class. It should treat source files as authoritative and avoid inventing provider fields.
An installed MCP client can inspect loaded transport descriptors when scoped, but this reference page itself is local documentation. It does not expose a standalone MCP resource.
Scopes
Reading this reference requires no runtime scope.
Runtime descriptor inspection uses administration.read through /api/v1/administration/mail/transports. Sending mail happens through MyronCMS mail callers and the active transport, not by granting callers direct access to these objects.
MailEnvelope Fields
Constructor fields:
| Field | Type | Required | Meaning |
|---|---|---|---|
to | string | Yes | Recipient email address. |
subject | string | Yes | Message subject. |
htmlBody | string | Yes | HTML message body. |
textBody | string | Yes | Plain text body. |
fromEmail | string | Yes | Sender email address. |
fromName | string | Yes | Sender display name. |
replyTo | ?string | No | Optional reply-to email address. |
headers | array<string, string> | No | Optional allowlisted Myron headers. |
toArray() emits:
[
'to' => $this->to,
'subject' => $this->subject,
'htmlBody' => $this->htmlBody,
'textBody' => $this->textBody,
'fromEmail' => $this->fromEmail,
'fromName' => $this->fromName,
'replyTo' => $this->replyTo,
'headers' => $this->headers,
]
fromArray() reads the same keys and casts missing scalar values to empty strings. It only preserves these header names:
| Header | Current behavior |
|---|---|
x-myron-context | Preserved when supplied in headers. |
x-myron-source | Preserved when supplied in headers. |
Other headers passed into fromArray() are ignored. Do not document arbitrary provider headers as core envelope fields.
MailDispatchResult Fields
Constructor fields:
| Field | Type | Required | Meaning |
|---|---|---|---|
ok | bool | Yes | Whether the transport completed successfully. |
transportId | string | Yes | Core slug such as smtp or extension id such as x.my_vendor.api. |
providerMessageId | ?string | No | Optional id returned by the provider on success. |
error | ?string | No | Stable error string on failure. |
Use the named constructors:
MailDispatchResult::ok('x.my_vendor.api', 'provider-message-id');
MailDispatchResult::failed('x.my_vendor.api', 'mail_provider_not_configured');
toArray() emits:
[
'ok' => $this->ok,
'transportId' => $this->transportId,
'providerMessageId' => $this->providerMessageId,
'error' => $this->error,
]
Artifacts
Source artifacts:
app/system/mail/MailEnvelope.phpapp/system/mail/MailDispatchResult.phpapp/system/mail/MailTransportInterface.php
Runtime usage:
MyronMailercreatesMailEnvelopefrom saved mail settings and message content.MyronSmtpTransportreadsMailEnvelopeand returnsMailDispatchResult.- Extension transports implement the same object contract.
Safety Boundary
Do not add fields in documentation before they exist in source. Provider-specific concepts such as categories, templates, attachments, batch sends, or webhook metadata are not current MailEnvelope fields.
Do not use the headers array as an escape hatch for arbitrary provider headers. The current fromArray() path allowlists only x-myron-context and x-myron-source.
Do not leak provider exception payloads that may contain secrets. Convert provider failures into stable error strings where possible.
Verification
Run:
php app/tests/verify-forms-mail-substrate.php
The test verifies the active transport implements MailTransportInterface, the SMTP descriptor is present, and a MailEnvelope round trip through toArray() and fromArray() preserves expected fields.
For documentation review, compare field tables directly against:
MailEnvelope::__construct()MailEnvelope::toArray()MailEnvelope::fromArray()MailDispatchResult::__construct()MailDispatchResult::ok()MailDispatchResult::failed()MailDispatchResult::toArray()
Failure Modes
| Failure | Likely cause | Safe response |
|---|---|---|
Header missing after fromArray() | Header name is not in the allowlist. | Use only current allowlisted headers or evaluate a source change separately. |
ok is false with no stable remediation | Transport returned a raw or vague provider error. | Map provider failures to stable error strings. |
| Provider payload needs unsupported fields | Provider has requirements outside the current envelope. | Use provider settings or a future contract; do not document unsupported core fields. |
| Caller treats descriptor listing as send access | Descriptor discovery was confused with mail dispatch authority. | Keep listing, setup, and send-time behavior separate. |