This page describes
lettr/lettr-laravel 2.7.0 and later. On 2.6.x the generated code looks different: DTO properties lose camelCase, Blade loops use $item->key, Mailables for Lettr templates set a subject, and none of the files carry a generated-file docblock. Upgrade with composer update lettr/lettr-laravel, then re-run the commands.Why Code Generation?
Using string literals for template slugs and merge tags is error-prone:LettrTemplate::WelcomEmail doesn’t exist, and WelcomeEmailData requires firstName and activationUrl.
Generate Everything at Once
Thelettr:init command can generate all code for you during setup:
Template Enum
Generate an enum containing all your template slugs:app/Enums/LettrTemplate.php:
.env) and generates a backed enum case for each one. The case name is the PascalCase version of the template slug, adjusted when PHP wouldn’t accept it:
Usage
Benefits
- Autocomplete - Your IDE suggests available templates
- Refactoring - Rename templates safely across your codebase
- Discovery - See all templates without leaving your editor
Template DTOs
Generate data transfer objects for each template’s merge tags:app/Dto/Lettr/:
- Required merge tags become required parameters and come first; optional ones default to
null. - Property names are camelCase:
first_nameandFIRST_NAMEbecome$firstName, andorderIdstays$orderId. If two keys would end up with the same name (FIRST_NAMEandfirst_namein one template), both keep their original key as the property name instead. toArray()maps the properties back to the original merge tag keys. Optional values you leave out are sent asnull.- Class names follow the same rules as enum cases, plus a
Datasuffix. PHP reserves more words for class names than for enum cases, so a template with the slugnewgetsNewTemplateData.
--template with a slug that doesn’t exist exits with a failure code.
Loops
A loop block gets its own item DTO, and the parent takes an array of them:toArray() sends null for it.
Usage
sendTemplate() accepts the DTO directly, because it implements Arrayable:
Benefits
- Required fields - Constructor enforces required merge tags
- Type hints - Know exactly what data each template needs
- Documentation - DTOs serve as living documentation
Mailable Classes
Generate a Mailable class, and a DTO for its merge tags, for each template:app/Mail/Lettr/. What they send depends on how you pull:
Lettr template Mailables
With--as-html or --skip-templates, the Mailable points at the template in Lettr. Editing the template in the dashboard changes the email without a deploy:
Blade Mailables
Without those flags, the template is saved as a Blade view and the Mailable renders it locally.LettrMailable passes whatever withMergeTags() returns — here the DTO’s toArray() — to the view. Loop items reach the view as arrays, so the pulled view reads them as $item['name'], and a loop you leave out renders nothing:
blade_path in config/lettr.php, so a custom path still resolves as long as it’s inside one of your view directories.
Usage
Either kind is sent like any other Mailable:Re-running the Command
Every run rewrites all the files it generates: Blade views, HTML files, DTOs, Mailables and the enum. Files that already existed are marked with ↻ in the output, followed by a warning:--dry-run to see which files would be overwritten.
Benefits
- Standard Laravel - Works with queues, events, and testing
- Encapsulation - Template logic stays in one place
- Familiar API - Same patterns you already use
Keeping Code in Sync
When you add or modify templates in Lettr, regenerate your code:Recommended Workflow
- Create or update a template in the Lettr dashboard
- Run
php artisan lettr:generate-enumandphp artisan lettr:generate-dtos - Commit the generated files
- Use the enum and DTO in your application code
Configuration
Customize paths and names inconfig/lettr.php:
Paths can be absolute or relative to your project root. Any key you leave out of a published
config/lettr.php falls back to its default.
Each namespace has to match its path under the autoload.psr-4 section of your composer.json, or the generated classes won’t load. The commands warn when they don’t match:
Artisan Commands Reference
What’s Next
Sending Emails
Put your generated code to use
Templates
Template versioning, projects, and sync commands
API Reference
Complete REST API documentation
Best Practices
Sending best practices and deliverability tips