plusforta / heykaution-mail
Shared mail layout components and Laravel mail theme for heykaution applications
Requires
- php: ^8.3
- illuminate/support: ^12.0|^13.0
- illuminate/view: ^12.0|^13.0
README
Shared mail layout components and Laravel mail theme for heykaution.de and heykaution-dmz.
Notification content stays in each application — this package only provides branding, layout building blocks, and helpers.
Installation
composer require plusforta/heykaution-mail:^1.0
The package is published on Packagist, so no VCS repository entry is needed.
HeykautionMailServiceProvider is auto-discovered by Laravel and registers:
- anonymous Blade components (
<x-mail-*>) - the heykaution mail markdown theme (
<x-mail::*>) - translations for component strings (
notifications.mail_closing, …), merged into each app'slang/*/notifications.phpgroup - the
formatIban()helper - configurable footer/legal/social URLs via
config/heykaution-mail.php
Configuration
Publish is optional — defaults work in heykaution.de (named routes + settings.links.social_media).
Apps without HK routes (e.g. DMZ) should set config/heykaution-mail.php:
return [
'app_url' => config('services.hk.app_url'),
'footer' => [
'social' => [
'facebook' => 'https://www.facebook.com/...',
'instagram' => 'https://www.instagram.com/...',
'linkedin' => 'https://linkedin.com/...',
],
],
];
Helpers used by the mail theme:
| Helper | Purpose |
|---|---|
heykaution_mail_app_url() | Public HK URL (heykaution-mail.app_url → services.hk.app_url → app.url) |
heykaution_mail_asset($path) | Local asset or absolute HK URL |
heykaution_mail_legal_url('terms'\|'privacy'\|'imprint') | Config URL, named route, or {app_url}/{locale}/agb fallback |
heykaution_mail_social_url('facebook'\|'linkedin'\|'instagram') | Config or legacy settings.links.social_media.* |
Custom components
These components are registered globally as <x-mail-*>.
<x-mail-highlight-box>
Green highlight box for emphasized content (e.g. changed account data, lock periods).
| Prop | Type | Default | Description |
|---|---|---|---|
align | string | 'left' | Text alignment inside the box (left, center, right, …) |
Slot: Markdown content (rendered via Illuminate\Mail\Markdown::parse, same as <x-mail::panel>).
<x-mail-highlight-box>
Old IBAN: {{ formatIban($oldIban) }}<br />
New IBAN: {{ formatIban($newIban) }}
</x-mail-highlight-box>
<x-mail-highlight-box align="left">
Left-aligned content
</x-mail-highlight-box>
<x-mail-device-info>
Displays device and connection details for a security-relevant change. Accepts both a DTO object (heykaution.de) and an array (heykaution-dmz).
| Prop | Type | Default | Description |
|---|---|---|---|
securityInformation | object\|array | — | Required. Device information (see structure below) |
Expected fields in securityInformation:
| Field | Type | Description |
|---|---|---|
ipAddress | string | Connection IP address |
device | string | Device name (e.g. smartphone) |
browser | string | Browser family |
os | string | Operating system |
timestamp | CarbonInterface\|string\|null | Time of the change; falls back to — when empty |
{{-- HK: SecurityInformation DTO --}}
<x-mail-device-info :security-information="$securityInformation" />
{{-- DMZ: array from sync queue --}}
<x-mail-device-info :security-information="[
'ipAddress' => '203.0.113.1',
'device' => 'desktop',
'browser' => 'Chrome',
'os' => 'macOS',
'timestamp' => '2026-06-09T10:30:00+02:00',
]" />
Translation key: notifications.device_info.text
<x-mail-closing>
Standard signature with greeting and team line (config('app.name')).
| Prop | Type | Description |
|---|---|---|
| — | — | No props |
Slot: None.
<x-mail-closing />
Translation keys: notifications.mail_closing.greeting, notifications.mail_closing.team
<x-mail-button-link-hint>
Fallback hint below a button when the button does not work in the mail client.
| Prop | Type | Default | Description |
|---|---|---|---|
url | string | — | Required. Target URL rendered as a clickable link |
<x-mail::button :url="$url">Confirm email address</x-mail::button>
<x-mail-button-link-hint :url="$url" />
Translation key: notifications.mail_button_link_hint
<x-mail-border>
Visual separator (blue line) between mail sections. Typically placed before the button link hint.
| Prop | Type | Description |
|---|---|---|
| — | — | No props |
Slot: None.
<x-mail-closing />
<x-mail-border />
<x-mail-button-link-hint :url="$url" />
<x-mail-table-row>
Table row with a label column and a value column. Use inside a <table>.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | Required. Left column label |
lastRow | bool | false | When true, no bottom border is rendered |
Slot: Right column cell content (HTML allowed).
<table width="100%" cellpadding="0" cellspacing="0">
<x-mail-table-row label="IBAN">
{{ formatIban($iban) }}
</x-mail-table-row>
<x-mail-table-row label="Amount" :last-row="true">
{{ $amount }}
</x-mail-table-row>
</table>
Mail theme components (<x-mail::*>)
This package overrides Laravel's default mail theme. Use these components in markdown notification templates.
<x-mail::message>
Wrapper for a complete mail. Renders layout, header, footer, and markdown body.
| Prop | Type | Description |
|---|---|---|
| — | — | No custom props |
Slot: Markdown content of the mail.
<x-mail::layout>
HTML shell (used internally by <x-mail::message>, rarely used directly).
| Prop | Type | Default | Description |
|---|---|---|---|
withClosing | bool | true | Controls optional closing behavior in the layout |
<x-mail::button>
Primary call-to-action button (heykaution blue).
| Prop | Type | Default | Description |
|---|---|---|---|
url | string | — | Required. Target URL |
trackingDisabled | bool | false | Sets data-pm-no-track on the link (Postmark) |
Slot: Button label.
<x-mail::button :url="$url">Confirm now</x-mail::button>
<x-mail::button :url="$url" :tracking-disabled="true">Without tracking</x-mail::button>
<x-mail::panel>, <x-mail::table>, <x-mail::header>, <x-mail::footer>, <x-mail::subcopy>
Standard Laravel mail components with heykaution styling. No additional props — slot content only.
<x-mail::panel>
Important notice with **markdown**.
</x-mail::panel>
Helper
formatIban(string $iban): string
Formats an IBAN with a space every 4 characters.
formatIban('DE89370400440532013000');
// → "DE89 3704 0044 0532 0130 00"
Usable directly in Blade templates:
{{ formatIban($iban) }}
Translations
The package loads the following keys under the notifications namespace (de/en):
| Key | Usage |
|---|---|
notifications.mail_closing.greeting | Signature greeting |
notifications.mail_closing.team | Team line (:app_name) |
notifications.mail_button_link_hint | Button fallback text (:url) |
notifications.device_info.text | Device info (:date, :time, :device, :ip) |
App-specific lang/*/notifications.php files can add more keys; Laravel merges the namespaces.
Example: notification template
Blade file in the app, e.g. resources/views/notifications/en/email/example.blade.php:
{{-- @formatter:off --}}
<x-mail::message>
**Hello {{ $notifiable->first_name }},**
Your IBAN was changed successfully.
<x-mail-highlight-box>
Old IBAN: {{ formatIban($oldIban) }}<br />
New IBAN: {{ formatIban($newIban) }}<br />
<br />
Payouts locked until: {{ $unlockAt }}
</x-mail-highlight-box>
If you did not make this change, you can revert it immediately:
<x-mail::button :url="$cancelUrl">
Revert change
</x-mail::button>
**Change details:**
<x-mail-device-info :security-information="$securityInformation" />
<x-mail-closing />
<x-mail-border />
<x-mail-button-link-hint :url="$cancelUrl" />
</x-mail::message>
Matching notification class (simplified):
public function toMail(mixed $notifiable): MailMessage
{
return (new MailMessage())
->subject('Your IBAN was changed')
->markdown('notifications.en.email.example', [
'notifiable' => $notifiable,
'oldIban' => 'DE89370400440532013000',
'newIban' => 'DE89370400440532013100',
'unlockAt' => '14.06.2026 10:30',
'cancelUrl' => 'https://heykaution.de/en/settings/security-lock/cancel/abc123',
'securityInformation' => [
'ipAddress' => '203.0.113.1',
'device' => 'desktop',
'browser' => 'Firefox',
'os' => 'Windows',
'timestamp' => now()->toIso8601String(),
],
]);
}
Local development
For parallel work on the package and consuming apps:
{
"repositories": [
{
"type": "path",
"url": "../heykaution-mail",
"options": { "symlink": true }
}
]
}
Changes in the package are then immediately visible in HK/DMZ.