Send emails directly from your forms using PHP's native mail() function or SMTP.
Want More Power?
Flick Pro adds file attachments, 6+ email providers (SendGrid, Mailgun, Amazon SES...), and advanced HTML templates with conditionals.
Configuration
Add mail configuration to your Flick setup:
$config = [ 'services' => [ 'mail' => [ 'fromAddress' => 'noreply@example.com', 'fromName' => 'My App', // Optional 'mailer' => [ 'transport' => 'mail' // or 'smtp' ] ] ] ]; $form = new Flick($config);
PHP mail() Transport
The simplest option. Uses your server's built-in mail function:
'mailer' => [ 'transport' => 'mail' ]
Tip
This config keeps working if you upgrade. With Flick Pro installed, $form->mail
becomes the Pro Mail service, which accepts the same mail
transport alongside smtp, ses, mailgun, sendgrid, postmark, mailjet,
and mailtrap. Nothing to change.
Warning
PHP mail() requires a properly configured mail server. Many shared hosts have this set up, but local development environments typically don't. Use SMTP for more reliable delivery.
On Windows with `sendmail_path` set, a failed send reports success
By default on Windows, PHP's mail() delivers using the SMTP and smtp_port
ini settings. Setting sendmail_path overrides both, and PHP then pipes the
message to that command through cmd.exe — which starts successfully whether or
not the command it was given exists. mail() reports success, so send()
returns true even though nothing was delivered.
Flick returns what mail() tells it, so there is nothing it can check to catch
this. With sendmail_path set to something broken, $form->mail->send() is not
a delivery signal on Windows.
Use the smtp transport instead. Flick connects to the
server itself, so an unreachable or rejecting server is a real false with the
reason available from the error bag — on every platform.
SMTP Transport
Connect directly to an SMTP server for reliable delivery. Only transport and host are required:
'mailer' => [ 'transport' => 'smtp', 'host' => 'smtp.example.com', ]
Defaults:
| Option | Default | Description |
|---|---|---|
port |
587 |
SMTP port |
encryption |
'tls' |
'tls' / 'starttls', 'ssl', or 'none' / '' — see below |
username |
'' |
Auth skipped if empty |
password |
'' |
Auth skipped if empty |
timeout |
30 |
Connection timeout in seconds |
verifyPeer |
true |
Verify the server's TLS certificate |
allowInsecureAuth |
false |
Permit sending credentials over an unencrypted connection |
What encryption accepts:
| Value | Behavior |
|---|---|
'tls' or 'starttls' |
STARTTLS, required — the send fails rather than quietly falling back to plaintext |
'ssl' |
Implicit TLS from the first byte, usually port 465 |
'none' or '' |
No encryption at all. Only for a local mail catcher — never over a network |
Leave it out, or set it to null, and you get 'tls'. Anything else throws an
InvalidArgumentException when the mailer is built, so a typo fails loudly
instead of quietly sending in the clear.
Full example with authentication:
'mailer' => [ 'transport' => 'smtp', 'host' => 'smtp.example.com', 'port' => 587, 'encryption' => 'tls', 'username' => 'your-username', 'password' => 'your-password' ]
Local development (Laravel Herd, Mailpit, etc.):
'mailer' => [ 'transport' => 'smtp', 'host' => '127.0.0.1', 'port' => 2525, 'encryption' => '', // Disable TLS for local testing ]
Warning
Flick refuses to send a username and password over an unencrypted connection —
send() returns false and puts "Refusing to send SMTP credentials over an
unencrypted connection" in the error bag. Local catchers usually don't need auth,
so the example above simply leaves username and password out. If yours does
require auth, add 'allowInsecureAuth' => true and keep it out of production.
Common SMTP settings:
| Provider | Host | Port | Encryption |
|---|---|---|---|
| Gmail | smtp.gmail.com | 587 | tls |
| Outlook | smtp.office365.com | 587 | tls |
| Yahoo | smtp.mail.yahoo.com | 587 | tls |
Basic Usage
Send a Simple Email
if ($form->mail->send('user@example.com', 'Hello!', 'This is the message body.')) { $form->successMessage('Email sent!'); } else { $form->errorMessage('Failed to send email.'); }
With Options
$form->mail->send('user@example.com', 'Hello!', 'Message body', [ 'fromAddress' => 'custom@example.com', 'fromName' => 'Custom Sender', 'cc' => 'copy@example.com', 'bcc' => 'hidden@example.com', 'replyTo' => 'reply@example.com', 'priority' => true // Mark as high priority ]);
Multiple Recipients
$form->mail->send( ['user1@example.com', 'user2@example.com'], 'Team Update', 'This message goes to everyone.' );
Send Form Data
Automatically format and send form submissions:
if ($form->submitted()) { $request = $form->request('Name[required], Email[required, email], Message[required]'); if ($form->ok()) { $form->mail->sendFormData( 'admin@example.com', 'New Contact Form Submission', $request ); } }
This sends a plain-text body like the following, plus an HTML version with the same fields laid out in a table:
Name: John Doe Email: john@example.com Message: Hello, I have a question...
Exclude Fields
Hide sensitive or unnecessary fields:
$form->mail->sendFormData('admin@example.com', 'Contact Form', $request, [ 'exclude' => ['_token', 'honeypot', 'password'] ]);
HTML Emails
Send both plain text and HTML versions (multipart/alternative):
$form->mail->send( 'user@example.com', 'Welcome!', 'Welcome to our site. Thanks for signing up!', // Plain text fallback [ 'html' => '<h1>Welcome!</h1><p>Thanks for signing up!</p>' ] );
Simple Variables
Use {{ variable }} placeholders with the data option:
$form->mail->send( $request['email'], 'Order Confirmation', 'Hi {{ name }}, your order #{{ order_id }} is confirmed.', [ 'html' => '<h1>Thanks, {{ name }}!</h1><p>Order #{{ order_id }} confirmed.</p>', 'data' => [ 'name' => $request['name'], 'order_id' => '12345' ] ] );
Tip
HTML variables are automatically escaped to prevent XSS attacks. Plain text variables are inserted as-is.
Methods
send()
Send an email message.
$form->mail->send( string|array $to, string $subject, string $body, array $options = [] ): bool
| Parameter | Type | Description |
|---|---|---|
$to |
string|array |
Recipient email address(es) |
$subject |
string |
Email subject line |
$body |
string |
Plain text message body |
$options |
array |
Additional options (see below) |
Options:
| Option | Type | Description |
|---|---|---|
html |
string |
HTML version of the email |
data |
array |
Variables for {{ placeholder }} replacement |
fromAddress |
string |
Override sender address |
fromName |
string |
Override sender name |
cc |
string|array |
Carbon copy recipient(s) |
bcc |
string|array |
Blind carbon copy recipient(s) |
replyTo |
string |
Reply-to address |
priority |
bool |
Mark as high priority |
Returns: true on success, false on failure.
sendFormData()
Send formatted form data as an email.
$form->mail->sendFormData( string|array $to, string $subject, array $formData, array $options = [] ): bool
| Parameter | Type | Description |
|---|---|---|
$to |
string|array |
Recipient email address(es) |
$subject |
string |
Email subject line |
$formData |
array |
Key-value pairs from form submission |
$options |
array |
Same as send(), plus exclude |
Additional Option:
| Option | Type | Description |
|---|---|---|
exclude |
array |
Field names to omit from the email |
Complete Example
<?php require 'vendor/autoload.php'; $form = new Flick\Flick([ 'services' => [ 'mail' => [ 'fromAddress' => 'noreply@myapp.com', 'fromName' => 'My App', 'mailer' => [ 'transport' => 'smtp', 'host' => 'smtp.example.com', 'port' => 587, 'encryption' => 'tls', 'username' => $_ENV['SMTP_USER'], 'password' => $_ENV['SMTP_PASS'] ] ] ] ]); $form->create('Name, Email, Phone, Message|textarea'); if ($form->submitted()) { $request = $form->request(' Name[required, min:2], Email[required, email], Phone[phone], Message[required, min:10] '); if ($form->ok()) { // Send notification to admin $sent = $form->mail->sendFormData( 'admin@myapp.com', 'New Contact Form Submission', $request ); // Send confirmation to user $confirmed = $form->mail->send( $request['email'], 'We received your message', "Hi {{ name }},\n\nThank you for contacting us. We'll respond within 24 hours.", ['data' => ['name' => $request['name']]] ); if ($sent && $confirmed) { $form->successMessage('Message sent! Check your email for confirmation.'); } else { $form->errorMessage('Sorry, your message could not be sent.'); } } } $form->create('Name, Email, Phone, Message|textarea');
Upgrading to Pro
Need more from your email setup? Flick Pro adds:
- File Attachments - PDFs, images, CSVs with fluent API
- 6+ Transport Providers - SendGrid, Mailgun, Amazon SES, Postmark, Mailjet, Mailtrap
- Advanced Templates - File-based templates with conditionals (
@if), nested data access, raw HTML output
// Pro: Attachments $form->mail ->attach('/path/to/invoice.pdf') ->send('customer@example.com', 'Your Invoice', 'Attached is your invoice.'); // Pro: SendGrid transport 'mailer' => [ 'transport' => 'sendgrid', 'key' => 'your-api-key' ]