BuiltEmail workspace

Insurance purchase details — provider

Source: App\Mail\InsuranceOrderConfirmed, app/Mail/InsuranceOrderConfirmed.php; resources/views/emails/insurance/purchase.blade.php using mail::message. Subject: New Insurance Purchase From Built! (unchanged). Suggested preheader: Insurance purchase details for {{product_name}}.

Common portable values

TokenExisting sourceHandling
{{provider_name}}provider.name ?? '', where provider = order.serviceProviderOptional escaped provider greeting, omitted as a whole if empty/null; do not invent another recipient.
{{product_name}}order.product.nameRequired original product display.
{{insured_name}}order.nameRequired named insured person, distinct from the purchaser and beneficiary.
{{purchase_amount}}order.currency . ' ' . order.amountRequired **raw** original display with a space; no number_format, comma insertion or fixed two decimals. Do not substitute receipt formatting.
{{purchased_by}}order.user?->first_name ?? 'N/A'Required row. Null user/name becomes N/A; empty string/0 remain. The separately bound user variable does not override this source expression.
{{product_type_name}}order.product.type->name()Required native enum display (Life Insurance / Motor Vehicle Insurance); do not infer from product text.
{{insured_phone}}order.phone_numberRequired original order phone, not buyer/provider/beneficiary phone.
{{app_name}}config('app.name')Original Thanks sign-off.
{{preheader}}Product summary aboveEscaped text, no underwriting/coverage guarantee.

Default logo/optional {{logo_url}} and shared badge CID/HTTPS policy: [shared-footer](../shared-footer.md).

Motor repeat contract

Original condition is strict enum identity: order.product.type === App\Enums\InsuranceTypes::MotorVehicleInsurance. Preserve the source enum/cast, not a loose guessed product-name test. Preview product_type_key is an adapter discriminator derived from that enum; it is not a printed token.

For every order.data entry, map {{motor_field_label}} to Str::headline(original key) and {{motor_field_value}} to its original scalar display (null to empty, 0 to 0). Preserve order and every entry: there is **no row cap**. The ready table marks one repeat row; native integration must foreach the original collection and escape label/value separately. No arbitrary HTML-row placeholder or untrusted raw HTML is accepted. Empty data renders no motor rows/caption/table; source motor creation normally requires cover_type, vehicle_registration_number and vehicle_classification. Empty/twelve-field fixtures test source-view behavior, not new creation rules. If stored values are nested/non-scalar, the original Blade is not a defined JSON renderer; make an explicit adapter/error-handling decision rather than silently serializing or dropping them.

Life and beneficiary values

Retain this whole section only when order.product.type === App\Enums\InsuranceTypes::LifeInsurance. All rows are unconditional inside that branch, including empty/0 values. Remove it completely for motor insurance and remove motor content for life insurance.

TokenExisting source
{{birth_date}}order.birth_date, original display; no new date conversion
{{age}}order.age, supplied stored age; do not recalculate at send time
{{gender}}order.gender
{{address}}order.address
{{nationality}}order.nationality?->name; null remains empty, not N/A
{{marital_status}}order.marital_status
{{occupation}}order.occupation
{{beneficiary_name}}order.beneficiary_name
{{beneficiary_phone}}order.beneficiary_phone_number
{{beneficiary_birth_date}}order.beneficiary_birth_date, original display
{{beneficiary_age}}order.beneficiary_age, no new calculation
{{beneficiary_relationship}}order.beneficiary_relationship
{{beneficiary_gender}}order.beneficiary_gender

Escape all fields as text; preserve the buyer/insured/beneficiary distinction. Missing mandatory model/product/enum context needs an explicit target-project decision. Do not introduce ID documents, bank details, policy dates, nationality-file URLs, claim information or other personal fields absent from this email. All demographic/vehicle samples here are fictional.

Trigger and delivery

InsuranceOrderController::changeState (:216–295) updates order/activity in a transaction. For status confirmed it validates a truthy serviceProvider.business_email with FILTER_VALIDATE_EMAIL, then queues this Mailable to that provider with existing internal BCC at :238. build() binds provider/order/user. The same operation queues a separate customer status update after the transaction. Preserve those audiences, ordering, route/authentication and status guards. Route POST insurance-orders/{id}/change-status: routes/api.php:224. The public changeStatus path restricts allowed transitions; do not add a confirmed-again send or different eligibility rule through HTML.

No explicit From/Reply-To override, PDF, email attachment or workflow URL exists. Keep native subject, queue(), To/BCC and transport/outbox policy. Confirmed-order provider purchase details do not independently prove that a NewInsurancePolicy has already been issued; policy creation is the separate completed branch. Product/identity files stored in models are not attached here.

Native integration and safety

Use the existing Mailable with a complete HTML Blade view, native enum condition/foreach and proposed plain-text alternative. Portable {{placeholder_name}} tokens are not automatically Blade; no new framework is required. Remove unselected branch wrappers in HTML/text and repeat all motor rows. Escape text/attributes, validate images separately and use one pass if replacing tokens. CID assets must actually be embedded or replaced with approved HTTPS assets. There are no legacy duplicate action-link fields because none is supplied.

Seven states cover motor/life, original null/empty fallbacks, supplied zero/ages as rendering-only checks, empty motor iterable, twelve motor rows and long life details. New creation validation does not necessarily accept each robustness fixture. Files: public/ready/insurance-provider-purchase.html/.txt and previews/insurance-provider-purchase-*.html/.txt. No separate per-email project-owned text source found. Browser checks do not verify real personal data, coverage/payment, actual Gmail/Outlook/iOS Mail/CID behavior or current production sending.