Choosing a sending method
PropOps Web supports two email sending methods. Each template can be configured independently.Setting up local email
Local email works immediately with no configuration. Templates are rendered fromviews/emails/ and sent via PHP mail().
Set your sender details
.env file:Configure your branding
Leave BREVO_API_KEY empty
Setting up Brevo
Create a Brevo account
Generate an API key
Add to your environment
Verify your sender domain
Set template values to Brevo IDs
How template resolution works
Each email type is mapped to anEMAIL_TEMPLATE_* variable in .env. The value determines how PropOps Web sends that email:
{"{{ params.COLUMN_NAME }}"} syntax — the same format Brevo uses — so migrating between local and Brevo is seamless.Customising templates
Editing an existing template
All 47 pre-built templates live inviews/emails/. Each template is a standalone HTML fragment that gets wrapped in layout.html.
Open the template file
views/emails/ — for example welcome.html.Edit the HTML
{"{{ params.VARIABLE_NAME }}"} placeholders for dynamic content. Check the existing template to see which variables are available.Test locally
http://localhost:8025 so you can preview your changes.Creating a new template
Create the HTML file
.html file in views/emails/. The filename should match the template name you’ll use in .env — for example my_custom_email.html.Add a subject line
Write your template content
layout.html (logo, footer, styling). You only need to write the inner content:Register in .env
EMAIL_TEMPLATE_* variable pointing to your template name:Send from code
EmailService::sendTemplate() with the env key:Editing the layout
The shared layout inviews/emails/layout.html wraps every template. It contains:
- The outer email structure (background, centring)
- Your brand logo (centred)
- The white content card
- The footer with
APP_URLand copyright - Dark mode styles
- Responsive breakpoints
layout.html to change the look of all emails at once. The placeholder {"{{ TEMPLATE_CONTENT }}"} is where each template’s content is injected.
Auto-injected variables
These variables are available in every template automatically:Environment configuration
Core settings
Template mappings
Each email type has anEMAIL_TEMPLATE_* variable. Set it to a local template name or a Brevo template ID:
Troubleshooting
Emails not being sent
Emails not being sent
- If using Brevo, check that
BREVO_API_KEYis set correctly in your.env - If using local, check your server’s
mail()function is working (php -r "mail('test@example.com','Test','Body');") - Verify the sender domain is confirmed in Brevo (if applicable)
- Check the Email Log in Admin → Email Log for error messages
Emails going to spam
Emails going to spam
- Ensure your sender domain has SPF, DKIM, and DMARC records configured
- Verify the domain in Brevo’s sender settings
- Use a professional sender address (avoid free email providers)
Template not rendering correctly
Template not rendering correctly
- Check the template file exists in
views/emails/with the correct filename - Verify placeholder names match exactly (case-sensitive):
{"{{ params.USER_NAME }}"}not{"{{ params.user_name }}"} - If the template falls back to the generic template, the specific file may be missing or misspelt
- Use Mailpit to preview rendered HTML during development
Switching between local and Brevo
Switching between local and Brevo
- To use a local template: set the env value to the template name (e.g.
welcome) - To use Brevo: set the env value to the numeric Brevo template ID (e.g.
30) - You can mix both — each template is independent