2026-07-15

Send PHP HTML mail with attachments

Stefan Bogdanescu

Stefan Bogdanescu

Founder & Senior Architect

Send PHP HTML mail with attachments

Sending PHP HTML Emails with Attachments: Mastering Multipart MIME Structure

As developers, we often encounter hurdles when trying to move beyond simple text communication. Sending rich HTML emails with attachments requires understanding the nuances of the Multi-part Internet Message (MIME) standard. Many developers, including those working with PHP's built-in mail() function, run into confusion when switching between simple text/html and complex structures like multipart/mixed.

This post will walk you through exactly how to structure your PHP mail content to successfully send an HTML email that includes file attachments.

The Challenge: Why Simple Headers Fail

You correctly identified the transition point: moving from a single Content-Type: text/html to Content-Type: multipart/mixed. The issue arises because the standard dictates that if you want to embed multiple distinct parts (like an HTML body and file attachments) into a single email, you must use a container type.

When you use text/html, the server expects only one stream of HTML data. When you introduce attachments, you are essentially introducing separate "parts" of the message, each needing its own header and boundary marker. Simply changing the main content type isn't enough; you need to define the structure within that container.

The Solution: Understanding multipart/mixed

The key to solving this is understanding the role of multipart/mixed. This MIME type acts as a container for multiple distinct message parts. Inside this container, each individual part (the HTML body, plain text alternative, and each attachment) must be clearly delineated using specific boundaries.

When constructing an email payload manually in PHP, you are essentially writing raw MIME text. You need to define the overall structure, then define the content type for every segment.

Structure Breakdown

A properly constructed multipart/mixed message looks like this:

  1. The Main Boundary: Starts with -- followed by the boundary string.
  2. The Mixed Type: Declares that the following content is a mix of different types.
  3. Part 1 (The HTML Body): Defines the actual email content, specifying Content-Type: text/html.
  4. Part 2 (Attachments): Each attachment must start with its own boundary and define its specific Content-Type (e.g., application/octet-stream) and filename using Content-Disposition.

Practical PHP Implementation Example

Since the native mail() function struggles with complex MIME construction, the most robust approach is to manually assemble the raw MIME message string before sending it via a method that supports raw content (like using PHPMailer or similar libraries, which abstract this complexity beautifully). However, for demonstration purposes, here is how the structure looks conceptually:

<?php
// Variables setup
$htmlBody = "<h1>Hello World!</h1><p>This is an HTML email with attachments.</p>";
$attachmentPath = 'document.pdf';
$attachmentName = basename($attachmentPath);

// 1. Define the boundaries
$boundary = md5(uniqid(rand(), true));
$separator = "\r\n--" . $boundary . "\r\n";

// 2. Construct the multipart/mixed message
$mime_message = "Content-Type: multipart/mixed; boundary=\"{$boundary}\"\r\n";

// --- Part 1: The HTML Body ---
$mime_message .= "{$separator}";
$mime_message .= "Content-Type: text/html; charset=UTF-8\r\n";
$mime_message .= "{$separator}";
$mime_message .= $htmlBody . "\r\n";

// --- Part 2: The Attachment ---
$mime_message .= "{$separator}";
// Note: This is the attachment part, not text/plain
$mime_message .= "Content-Type: application/octet-stream; name=\"{$attachmentName}\"\r\n";
$mime_message .= "Content-Disposition: attachment; filename=\"{$attachmentName}\"\r\n";
$mime_message .= "\r\n"; // Blank line separates the part data from the next boundary

// 3. Closing Boundary
$mime_message .= "{$separator}--";

// In a real application, you would now send this $mime_message content via an SMTP library
// or use a dedicated library like PHPMailer to handle the final transmission.
echo $mime_message;
?>

Best Practices for Robust Email Sending

When dealing with complex MIME structures, remember these best practices:

  1. Use Libraries: While understanding the raw MIME structure is crucial, for production systems, relying on well-tested libraries like PHPMailer or Symfony Mailer is highly recommended. These libraries handle all the tedious boundary management, character encoding (like UTF-8), and edge cases automatically, saving significant development time and reducing security risks.
  2. Encoding: Always explicitly set the character set, preferably UTF-8, for all parts of your message to ensure international characters display correctly across different email clients.
  3. Keep it Simple (When Possible): If you only need simple text and no attachments, stick to a plain text/plain or text/html format. Avoid overcomplicating the MIME structure unless absolutely necessary.

Mastering this multipart logic is fundamental to effective backend communication. For more insights into building robust applications with PHP, explore the resources available at laravelcompany.com.

Note: Blog content is currently available in English.

Tags:

Enhance your marketing setup with your own email marketing platform.

Join the growing number of SaaS platforms using Laravel Mail to offer email marketing solutions to their customers.