data types and standard library
Email and MIME Handling
PHP applications send email for account verification, password resets, invoices, receipts, notifications, alerts, and support workflows. The hard part is not only "send a string"; it is building a safe message and handing delivery to a reliable mailer or provider.
For production, prefer a maintained mailer library or transactional email provider. They handle MIME boundaries, encodings, SMTP/API details, attachments, retries, and delivery diagnostics better than hand-built calls to mail().
Validate recipient addresses
Validate addresses before building the message.
<?php
declare(strict_types=1);
function requireEmailAddress(string $email): string
{
$email = trim($email);
if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidArgumentException('Invalid email address.');
}
return strtolower($email);
}
echo requireEmailAddress(' NIA@example.com ') . PHP_EOL;
// Prints:
// nia@example.com
This validates syntax, not deliverability. A syntactically valid address can still bounce.
Prevent header injection
Email headers must not contain raw newlines from user input. A malicious value could try to add extra headers.
<?php
declare(strict_types=1);
function assertHeaderValue(string $value): string
{
if (str_contains($value, "\r") || str_contains($value, "\n")) {
throw new InvalidArgumentException('Header value contains a newline.');
}
return $value;
}
try {
assertHeaderValue("Welcome\nBcc: attacker@example.com");
} catch (InvalidArgumentException $exception) {
echo $exception->getMessage() . PHP_EOL;
}
// Prints:
// Header value contains a newline.
Mailer libraries usually protect this boundary, but you still need to understand why raw header concatenation is risky.
Encode non-ASCII header text
Headers have different encoding rules from message bodies. Use MIME-aware encoding for header text.
<?php
declare(strict_types=1);
$subject = 'Résumé received';
$encodedSubject = mb_encode_mimeheader($subject, 'UTF-8');
echo str_contains($encodedSubject, '=?UTF-8?') ? 'encoded subject' : $encodedSubject;
echo PHP_EOL;
// Prints:
// encoded subject
Do not assume a subject or sender display name contains only ASCII.
Keep plain text and HTML bodies separate
Many emails include both a plain text body and an HTML body.
<?php
declare(strict_types=1);
$name = 'Nia & Co';
$plainText = 'Hello ' . $name . ', your order is ready.';
$html = '<p>Hello ' . htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . ', your order is ready.</p>';
echo $plainText . PHP_EOL;
echo $html . PHP_EOL;
// Prints:
// Hello Nia & Co, your order is ready.
// <p>Hello Nia &amp; Co, your order is ready.</p>
HTML email still needs HTML escaping. Plain text and HTML are different output contexts.
Attachments need MIME metadata
An attachment is more than a file path. You need the display filename, MIME type, and content source.
<?php
declare(strict_types=1);
function attachmentMetadata(string $filename, string $mimeType): array
{
if (basename($filename) !== $filename || $filename === '') {
throw new InvalidArgumentException('Attachment filename is invalid.');
}
if (!str_contains($mimeType, '/')) {
throw new InvalidArgumentException('Attachment MIME type is invalid.');
}
return [
'filename' => $filename,
'mimeType' => $mimeType,
];
}
$attachment = attachmentMetadata('invoice-2026-001.pdf', 'application/pdf');
echo $attachment['filename'] . ' / ' . $attachment['mimeType'] . PHP_EOL;
// Prints:
// invoice-2026-001.pdf / application/pdf
Validate attachments before passing them to a mailer, especially when files originate from uploads or generated storage.
Queue important mail
Sending email during a web request can make the user wait and makes failures awkward. Many applications record an email job, then a worker sends it.
<?php
declare(strict_types=1);
$job = [
'type' => 'send_email',
'template' => 'order.receipt',
'recipient' => 'nia@example.com',
];
echo $job['type'] . ' / ' . $job['template'] . PHP_EOL;
// Prints:
// send_email / order.receipt
Queues also make retries, failure logs, and provider outages easier to handle.
What to remember
Validate addresses, protect headers from newlines, encode header text, escape HTML bodies, describe attachments with MIME metadata, and use a proper mailer or provider for production delivery. Treat email as an external integration with logs and failure handling, not as a simple string write.
Practice
Task: Prepare a safe email message
Write a small helper that prepares email message data without sending it.
Requirements
- Use
declare(strict_types=1);. - Validate and normalise the recipient email address.
- Reject subject text containing
\ror\n. - Encode the subject with
mb_encode_mimeheader(). - Build a plain text body.
- Build an HTML body and escape user-controlled text.
- Return a message array containing recipient, encoded subject, plain text body, and HTML body.
- Show one valid message and one rejected subject.
- Include the expected output as comments in the same PHP code block.
Do not call mail(). The goal is safe message preparation before a real mailer sends it.
Show solution
<?php
declare(strict_types=1);
function prepareWelcomeEmail(string $recipient, string $subject, string $name): array
{
$recipient = trim($recipient);
if (filter_var($recipient, FILTER_VALIDATE_EMAIL) === false) {
throw new InvalidArgumentException('Invalid recipient address.');
}
if (str_contains($subject, "\r") || str_contains($subject, "\n")) {
throw new InvalidArgumentException('Subject contains a newline.');
}
$name = trim($name);
if ($name === '') {
throw new InvalidArgumentException('Recipient name is required.');
}
return [
'recipient' => strtolower($recipient),
'subject' => mb_encode_mimeheader($subject, 'UTF-8'),
'text' => 'Hello ' . $name . ', welcome to the course.',
'html' => '<p>Hello ' . htmlspecialchars($name, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8') . ', welcome to the course.</p>',
];
}
$message = prepareWelcomeEmail(' NIA@example.com ', 'Welcome', 'Nia & Co');
echo $message['recipient'] . PHP_EOL;
echo $message['subject'] . PHP_EOL;
echo $message['html'] . PHP_EOL;
try {
prepareWelcomeEmail('nia@example.com', "Welcome\nBcc: attacker@example.com", 'Nia');
} catch (InvalidArgumentException $exception) {
echo $exception->getMessage() . PHP_EOL;
}
// Prints:
// nia@example.com
// Welcome
// <p>Hello Nia &amp; Co, welcome to the course.</p>
// Subject contains a newline.
The helper prepares the message data safely but leaves actual delivery to a mailer. It validates the recipient, protects the header boundary, and escapes the HTML body separately from the plain text body.