Discover how to debug and fix common Statamic contact form email problems, including blank message fields and configuration conflicts.
Sometimes the best tutorials come from real debugging sessions. Today, I encountered a frustrating issue with my Statamic contact form: emails weren't being sent, and when they were, the message field was completely blank. Here's how I diagnosed and fixed these issues, step by step.
The Problem
My Statamic site had a contact form that looked perfect on the frontend, but behind the scenes, it was failing in two critical ways:
- Emails weren't being sent reliably - Some would go through, others wouldn't
- The message field was always blank - Even when emails were delivered, the most important field was empty
If you've faced similar issues, you know how frustrating this can be. Let's walk through the debugging process and solutions.
Discovery Phase: Understanding the Issue
The first step was understanding what was actually happening. I started by checking the Laravel logs:
tail -100 storage/logs/laravel.log | grep -E "(mail|email|message|contact)" -i
This revealed several critical errors:
[2025-08-17 13:03:49] Production.DEBUG: Cannot render an object variable as a string: {{ message }}
This error told me that the message field was being passed as an object, not a string - a common issue when Statamic's field augmentation system meets email templates.
Issue #1: Duplicate Mail Configuration
While investigating, I discovered duplicate MAIL_
settings in my .env
file:
# First set of configurations
MAIL_MAILER=log
MAIL_HOST=email-smtp.us-east-1.amazonaws.com
MAIL_PORT=587
MAIL_USERNAME=your-ses-smtp-username
MAIL_PASSWORD=your-ses-smtp-password
# ... later in the file ...
# Duplicate configurations (causing conflicts!)
MAIL_MAILER=smtp
MAIL_HOST=email-smtp.us-east-1.amazonaws.com
MAIL_PORT=587
MAIL_USERNAME=ACTUAL_USERNAME_HERE
MAIL_PASSWORD=ACTUAL_PASSWORD_HERE
The Problem: Laravel was reading conflicting values, with the first MAIL_MAILER=log
potentially overriding the actual SMTP configuration.
The Solution: Clean up the .env
file to have only one set of mail configurations:
# Email Configuration - AWS SES SMTP
MAIL_MAILER=smtp
MAIL_HOST=email-smtp.us-east-1.amazonaws.com
MAIL_PORT=587
MAIL_USERNAME=YOUR_SES_USERNAME
MAIL_PASSWORD=YOUR_SES_PASSWORD
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS="noreply@yourdomain.com"
MAIL_FROM_NAME="${APP_NAME}"
MAIL_TO_ADDRESS="contact@yourdomain.com"
Issue #2: Message Field Rendering as Object
The more complex issue was the message field showing up blank in emails. The error log showed that Statamic was passing the message as a Statamic\Fields\Value
object rather than a plain string.
Understanding the Root Cause
When Statamic processes form submissions, it augments the field values, wrapping them in Value objects that provide additional functionality. This is great for templating but causes issues when email templates expect plain strings.
Initial Attempt: Custom Data in Form YAML
My first attempt was to pass custom data in the form configuration:
email:
-
to: '{{ config:mail.to_address }}'
from: '{{ config:mail.from_address }}'
subject: 'Contact Form: {{ subject }}'
html: emails/contact
text: emails/contact_text
data:
name: '{{ name }}'
email: '{{ email }}'
message: '{{ message }}' # This still passed as object!
This didn't work because the data was still being augmented.
The Working Solution: Using Fields Loop
The solution was to remove the custom data and use the {{ fields }}
loop in the email template, which properly handles Value objects:
# In resources/forms/contact.yaml
email:
-
to: '{{ config:mail.to_address }}'
from: '{{ config:mail.from_address }}'
reply_to: '{{ email }}'
subject: 'Contact Form Submission: {{ subject }}'
html: emails/contact
text: emails/contact_text
# No custom data field - let Statamic handle it
Then in the email template:
{{ fields }}
{{ if value && fieldtype != 'spacer' }}
<div class="field">
<span class="label">{{ display }}</span>
<div class="value">
{{ if handle == 'email' }}
<a href="mailto:{{ value }}">{{ value }}</a>
{{ else }}
{{ value }}
{{ /if }}
</div>
</div>
{{ /if }}
{{ /fields }}
Issue #3: Message Formatting and Spacing
Once the message was displaying, I noticed the formatting was off - too much padding and poor paragraph handling.
The Bard Editor Experiment
I initially tried using Statamic's Bard rich text editor:
handle: message
field:
type: bard
save_html: true
buttons:
- bold
- italic
- unorderedlist
- orderedlist
While this provided rich text capabilities, it introduced complexity and spacing issues in the email templates. The HTML output was difficult to style consistently.
The Simple Solution: Textarea with nl2br
I reverted to a simple textarea with proper line break handling:
handle: message
field:
display: Message
type: textarea
required: true
validate:
- required
- min:10
character_limit: 5000
rows: 8
And in the email template:
{{ if handle == 'message' }}
<div class="message-content">
{{ value | nl2br | raw }}
</div>
{{ /if }}
The nl2br
filter converts line breaks to <br>
tags, and raw
outputs the HTML without escaping. This preserves paragraph formatting while keeping things simple.
Testing the Solution
To verify everything was working, I created a test script using Laravel's Tinker:
php artisan tinker
$form = \Statamic\Facades\Form::find('contact');
$submission = $form->makeSubmission()->data([
'name' => 'Test User',
'email' => 'test@example.com',
'subject' => 'Test Subject',
'message' => "First paragraph here.\n\nSecond paragraph here.",
'phone' => '555-1234'
]);
$email = new \Statamic\Forms\Email(
$submission,
[
'to' => config('mail.to_address'),
'from' => config('mail.from_address'),
'subject' => 'Test Email',
'html' => 'emails/contact',
'text' => 'emails/contact_text'
],
\Statamic\Facades\Site::current()
);
Mail::send($email);
echo 'Test email sent successfully';
Key Takeaways
-
Check for duplicate configurations - Always search your entire .env
file for duplicates when debugging configuration issues.
-
Understand Statamic's augmentation - Field values in Statamic are often Value objects, not plain strings. Use the {{ fields }}
loop or access the value property correctly.
-
Keep it simple - A textarea with nl2br
filtering is often better than a complex rich text editor for contact forms.
-
Test incrementally - Use Tinker to test email sending separately from form submission to isolate issues.
-
Check the logs - Laravel's debug logs often contain the exact error message you need to understand the problem.
The Final Working Configuration
Here's what finally worked:
Form Configuration (resources/forms/contact.yaml)
title: 'Contact Form'
handle: contact
fields:
- handle: name
field:
type: text
required: true
- handle: email
field:
type: text
input_type: email
required: true
- handle: subject
field:
type: text
required: true
- handle: message
field:
type: textarea
required: true
rows: 8
email:
-
to: '{{ config:mail.to_address }}'
from: '{{ config:mail.from_address }}'
reply_to: '{{ email }}'
subject: 'Contact Form: {{ subject }}'
html: emails/contact
text: emails/contact_text
Email Template (resources/views/emails/contact.antlers.html)
{{ fields }}
{{ if value && fieldtype != 'spacer' }}
<div class="field">
<span class="label">{{ display }}</span>
<div class="value">
{{ if handle == 'email' }}
<a href="mailto:{{ value }}">{{ value }}</a>
{{ elseif handle == 'message' }}
<div class="message-content">
{{ value | nl2br | raw }}
</div>
{{ else }}
{{ value }}
{{ /if }}
</div>
</div>
{{ /if }}
{{ /fields }}
Conclusion
Debugging email issues in Statamic requires understanding how the system processes and augments data. The key is recognizing that Statamic's Value objects need special handling in email templates, and that simpler solutions (like textarea with nl2br) often work better than complex ones (like rich text editors).
If you're facing similar issues, start by checking your configuration for duplicates, understand how your data is being passed to templates, and don't be afraid to simplify your approach. Sometimes the best solution is the simplest one.
Remember: when debugging email issues, always check your logs, test incrementally, and understand the data types being passed between components. Happy debugging!