VOOZH about

URL: https://deepwiki.com/hypervel/mail/5.2-mailable-lifecycle-and-preparation

⇱ Mailable Lifecycle and Preparation | hypervel/mail | DeepWiki


Loading...
Menu

Mailable Lifecycle and Preparation

This document explains the internal lifecycle of a Mailable instance as it is prepared for delivery. It covers the preparation pipeline that occurs before a mailable is sent or rendered, including the build() method invocation, hydration from optional envelope(), content(), headers(), and attachments() methods, view building, and view data aggregation.

For information about creating mailable classes and their structure, see Creating Mailable Classes. For details about the queue integration and asynchronous sending, see Queue Integration.


Preparation Pipeline Overview

The preparation pipeline is the core process that transforms a Mailable instance into a fully-configured message ready for delivery. This pipeline is invoked automatically whenever a mailable is sent, queued, or rendered.

The entry point is the prepareMailableForDelivery() method, which executes a series of steps in a fixed order:

  1. Build Phase: Invokes the optional build() method via dependency injection
  2. Headers Hydration: Processes custom headers from the headers() method
  3. Envelope Hydration: Extracts sender, recipients, subject, tags, and metadata from the envelope() method
  4. Content Hydration: Extracts view, HTML, text, or Markdown content from the content() method
  5. Attachments Hydration: Collects attachments from the attachments() method

Pipeline Execution Flow


Sources: src/Mailable.php1340-1353 src/Mailable.php163-182 src/Mailable.php236-248


The Build Phase

The first step in the preparation pipeline is the optional build() method invocation. This method, if defined on the mailable class, is called with dependency injection support, allowing constructor dependencies to be resolved from the container.

Build Method Invocation

The build phase occurs at src/Mailable.php1342-1347:

if (method_exists($this, 'build')) {
 $container = ApplicationContext::getContainer();
 method_exists($container, 'call')
 ? $container->call([$this, 'build'])
 : call([$this, 'build']);
}

The method uses method_exists() to check for the presence of a build() method, then invokes it using the container's call() method if available, falling back to a direct call helper otherwise. This allows the build() method to type-hint any dependencies it needs.

Build Method Purpose

The build() method is typically used to:

  • Set recipients using $this->to(), $this->cc(), $this->bcc()
  • Configure the sender with $this->from()
  • Set the subject with $this->subject()
  • Specify the view/Markdown template with $this->view() or $this->markdown()
  • Attach files with $this->attach() or related methods
  • Pass data to views with $this->with()
  • Add custom headers, tags, or metadata

Build Phase vs. Modern Methods

ApproachDescriptionUse Case
build() methodTraditional approach, uses fluent methodsLegacy compatibility, complex logic
envelope() methodReturns an Envelope instanceModern approach for sender/recipients/subject
content() methodReturns a Content instanceModern approach for view/content configuration
attachments() methodReturns attachment instancesModern approach for file attachments

Sources: src/Mailable.php1342-1347


Hydration Phases

After the build phase, the mailable undergoes four hydration phases that extract configuration from optional methods and merge them into the mailable's properties. These phases execute in sequence and allow for a more declarative mailable structure.

Headers Hydration

The headers hydration phase processes custom email headers defined in an optional headers() method. This method should return a Headers instance with message ID, references, and custom text headers.

Hydration Process


The implementation at src/Mailable.php1358-1379 uses the withSymfonyMessage() callback pattern to directly manipulate the Symfony message headers:

Header TypePropertyAction
Message ID$headers->messageIdAdds Message-Id header via addIdHeader()
References$headers->referencesAdds References header via addTextHeader()
Custom Text$headers->textAdds each key-value pair via addTextHeader()

Sources: src/Mailable.php1358-1379

Envelope Hydration

The envelope hydration phase extracts addressing information, subject, tags, metadata, and Symfony message callbacks from an optional envelope() method. This is the modern, declarative approach to configuring message envelope data.

Envelope Data Structure


The hydration logic at src/Mailable.php1384-1417 iterates through each envelope property and applies it to the mailable using the appropriate fluent methods. This allows the envelope() method to coexist with direct property setting or build() method configuration.

Address Handling

Addresses in the envelope are represented as Mailables\Address instances (defined in src/Mailables/Envelope.php1-289) with address and name properties. The hydration process normalizes these to the internal format used by the mailable.

Sources: src/Mailable.php1384-1417 src/Mailables/Envelope.php1-289

Content Hydration

The content hydration phase extracts view, HTML, text, and Markdown content configuration from an optional content() method. This method should return a Content instance that specifies how the email body should be rendered.

Content Configuration Flow


The implementation at src/Mailable.php1422-1453 sequentially checks each content property and applies it to the mailable. The content types are:

Content TypePropertyMethod CalledPurpose
Blade Viewcontent->viewview()Traditional Blade template path
HTML Viewcontent->htmlview()HTML string or path
Plain Textcontent->texttext()Plain text view path
Markdowncontent->markdownmarkdown()Markdown template path
HTML Stringcontent->htmlStringhtml()Raw HTML content
View Datacontent->withwith()Data to pass to views

Sources: src/Mailable.php1422-1453

Attachments Hydration

The final hydration phase processes attachments from an optional attachments() method. This method can return a single attachment or an array/collection of attachments implementing the Attachable contract or Attachment instances.

Attachment Hydration Process

The hydration at src/Mailable.php1458-1471 uses the following logic:

if (method_exists($this, 'attachments')) {
 $attachments = $this->attachments();
 
 Collection::make(is_object($attachments) ? [$attachments] : $attachments)
 ->each(function ($attachment) {
 $this->attach($attachment);
 });
}

This automatically normalizes both single attachments and arrays/collections, then delegates to the attach() method which handles different attachment types:

  • File paths: Direct file system paths
  • Attachment instances: Fluent attachment objects with options
  • Attachable implementations: Objects that can convert themselves to attachments

Sources: src/Mailable.php1458-1471 src/Mailable.php793-809


View Building

After all hydration phases complete, the mailable builds its view representation. This is a two-step process: determining which view type to use, and then constructing the view data that will be passed to the rendering engine.

View Type Resolution

The buildView() method at src/Mailable.php255-280 determines the view type based on which properties are set, checking in priority order:

View Type Decision Tree

















































PriorityProperty CheckedReturn ValueDescription
1$this->html['html' => HtmlString, 'text' => textView or null]Raw HTML content
2$this->markdown['html' => Closure, 'text' => Closure]Markdown rendering closures
3Both $this->view and $this->textView[view, textView]HTML and text Blade templates
4Only $this->textView['text' => textView]Plain text only
5Only $this->viewviewHTML Blade template only
6None set''Empty email (unusual)

Markdown View Building

When Markdown is used, buildMarkdownView() at src/Mailable.php287-295 creates two closures:

return [
 'html' => $this->buildMarkdownHtml($data),
 'text' => $this->buildMarkdownText($data),
];

These closures are invoked later by the Mailer during rendering, allowing the Markdown renderer to access both the view data and the message-specific data passed by the mailer.

Sources: src/Mailable.php255-280 src/Mailable.php287-295

View Data Aggregation

The buildViewData() method at src/Mailable.php302-317 aggregates data from three sources, merged in order of precedence:

Data Aggregation Pipeline


Data Source Precedence

OrderSourceDescriptionExample
1$this->viewDataExplicit data set via with()$this->with('order', $order)
2static::$viewDataCallbackGlobal callback registered via buildViewDataUsing()Application-wide data injection
3Public propertiesAutomatically included via reflectionAny public property on the mailable class

Public Property Reflection

The reflection logic at src/Mailable.php310-314 includes public properties that meet two criteria:

  1. Initialized: The property has been assigned a value
  2. Not from base class: The property is declared on the mailable subclass, not on the Mailable base class itself

This automatic inclusion allows for a clean, declarative style:


Static View Data Callback

The static::$viewDataCallback is registered globally via buildViewDataUsing() at src/Mailable.php1496-1499 and receives the mailable instance as an argument. This allows application-wide view data injection for all mailables.

Sources: src/Mailable.php302-317 src/Mailable.php1496-1499


Message Composition

After view building, the mailable composes the final message by applying all configuration to a Message instance. This happens during the send() method invocation at src/Mailable.php172-180:

return $mailer->send($this->buildView(), $this->buildViewData(), function ($message) {
 $this->buildFrom($message)
 ->buildRecipients($message)
 ->buildSubject($message)
 ->buildTags($message)
 ->buildMetadata($message)
 ->runCallbacks($message)
 ->buildAttachments($message);
});

Message Building Chain


Building Methods Reference

MethodLinesPurposeApplied From
buildFrom()367-374Sets sender address$this->from property
buildRecipients()379-388Sets to, cc, bcc, replyTo$this->to, $this->cc, $this->bcc, $this->replyTo arrays
buildSubject()393-402Sets subject line$this->subject or auto-generated from class name
buildTags()447-456Adds tag headers$this->tags array
buildMetadata()461-470Adds metadata headers$this->metadata array
runCallbacks()475-482Invokes custom callbacks$this->callbacks array
buildAttachments()407-424Attaches files$this->attachments, $this->rawAttachments, $this->diskAttachments

Subject Auto-Generation

If no subject is set, buildSubject() generates one from the class name at src/Mailable.php398:

$message->subject(Str::title(Str::snake(class_basename($this), ' ')));

Example: OrderShipped becomes "Order Shipped"

Attachment Building

The buildAttachments() method processes three types of attachments:

  1. File attachments ($this->attachments): File paths with options
  2. Raw attachments ($this->rawAttachments): In-memory data
  3. Disk attachments ($this->diskAttachments): Files from storage disks

Disk attachments are handled specially by buildDiskAttachments() at src/Mailable.php429-442 which retrieves file content from the configured storage disk and attaches it with the correct MIME type.

Sources: src/Mailable.php163-182 src/Mailable.php367-424 src/Mailable.php447-482


Invocation Points

The preparation pipeline is invoked automatically at three key points in the mailable lifecycle:

Lifecycle Invocation Map


Send Method Invocation

When send() is called at src/Mailable.php163-182 it:

  1. Wraps execution in withLocale() for proper locale handling
  2. Calls prepareMailableForDelivery()
  3. Resolves the mailer instance if needed
  4. Invokes mailer->send() with view and callbacks

Queue Method Invocation

When queue() or later() is called at src/Mailable.php187-217 the mailable is wrapped in a SendQueuedMailable job and pushed to the queue without preparation. The preparation occurs later when the queue worker processes the job and calls send() on the mailable.

Render Method Invocation

When render() is called at src/Mailable.php236-248 it:

  1. Wraps execution in withLocale()
  2. Calls prepareMailableForDelivery()
  3. Invokes mailer->render() to get the HTML string
  4. Returns the rendered content

This is useful for testing or generating email previews without actually sending.

Sources: src/Mailable.php163-182 src/Mailable.php187-217 src/Mailable.php236-248


Complete Preparation Sequence

The following diagram shows the complete preparation sequence with all components:

End-to-End Preparation Flow


Sources: src/Mailable.php163-182 src/Mailable.php1340-1353 src/Mailable.php255-280 src/Mailable.php302-317