BuiltEmail workspace

Invoice notification contract

Purpose: a business sends an invoice to its customer. Baseline: App\Mail\invoice and resources/views/emails/invoice/invoice.blade.php. Referenced queue callers include emailsController::sendinvoice and SendSelectedInvoices. See email-catalog.md for exact source lines; the Mailable definition alone does not prove production delivery.

Suggested subject: Invoice #{{invoice_number}}. This preserves the current subject pattern.

Suggested preheader: Invoice {{invoice_number}} from {{business_name}}. {{currency}} {{amount_due}} due by {{due_date}}.

Portable placeholder contract

TokenExisting Laravel source / derivationRequirement
{{logo_url}}Deployment asset value for the existing Built app_name PNG; not a business logoOptional deployment override; default is the verified project HTTPS Built PNG. Replace its src with an approved URL or matching CID if needed.
{{preheader}}Text assembled from invoice->invoice_number, business->name, invoice->fx_currency, invoice->amount_due and invoice->end_dateRequired; escaped text
{{business_name}}$business->nameRequired; repeated in heading, note label and sign-off
{{invoice_number}}$invoice->invoice_numberRequired; preserve as text, including leading zeros
{{currency}}$invoice->fx_currencyRequired; do not substitute business/base currency
{{amount_due}}number_format($invoice->amount_due, 2)Required; same due amount, not invoice total or amount_paid
{{due_date}}$invoice->end_dateRequired; format the same value without inventing a deadline
{{invoice_url}}$invoice->linkRequired; validated complete existing URL
{{invoice_action_label}}$can_pay ? 'View and pay invoice' : 'View invoice'Required derived label; never accept arbitrary user-supplied label
{{invoice_action_context}}$can_pay ? 'Opens your invoice, where you can review the details and payment options.' : 'Opens your invoice so you can review the details.'Required derived explanation
{{merchant_message}}$messageOptional; remove marked table if absent. Plain text contract with newlines preserved; see rich-message decision below

There is no new per-recipient greeting in this template. Recipient addresses stay with the existing caller's Mail::to/BCC logic. The sample customer's identity in the workspace header describes the audience and is not a new Laravel data dependency.

States and existing values outside the HTML

URL and legacy fields

invoice_url maps to invoice->link, not a new checkout endpoint. The current link can be a short URL generated by InvoiceWasCreated, which builds a destination at /viewinvoice/{uuid}. The legacy mailinvoiceJob separately builds button.link from /viewinvoice/{enc_id}; it is an older contract and is not interchangeable without investigation. Neither button.link nor a second payment_url token is needed for this current Mailable. The sign-in template's link/resetLink fields belong to a different notification.

Keep the current business From name and Reply-To fallback (business email, otherwise owner email), the subject pattern and attached PDF. Do not wire the sample preview-action.html URL into Laravel. Every populated demo action is a local explanation, not an application endpoint.

Plain text and integration

ready/invoice.txt is the portable text alternative. Populated .txt files sit beside each state preview. In Blade, use the same actual values and conditional message section in a text view. Do not include the optional section's token when the message is absent.

Use a dedicated full-document Blade view, convert portable token names explicitly and preserve existing data bindings. The raw baseline message output must not be copied as an untrusted raw HTML slot. Refer to integration-notes.html for escaping, URL validation, images, provider limitations and email-client testing.

Full-view merchant-note alias

When converting Markdown to a complete regular HTML view, explicitly bind the private constructor message to a nonreserved name such as invoice_message. Map merchant_message to that alias and keep its visibility predicate separate from rich-text normalization. Laravel's $message mail helper is needed for native image embedding and must not be treated as merchant text. This is a migration detail, not a claim that the existing Markdown body is broken. Apply the same note and condition in plain text; retain all PDF and extra-attachment bindings.