Send an Email with Attachments in PHP

Every web application uses the mail feature to send emails to subscribers for various purposes, like sending newsletters, verification emails, etc. Learn how to send an attachment with an email in PHP.

Send Email with Attachment in PHP

Sending emails from a web application is one of the most commonly used features. Web applications send emails to users for registration and verification, password recovery, transactional emails, marketing and promotional emails and reminder emails. In this post, we will learn how to upload files and send an email with multiple attachments in PHP in simple and easy steps. 

PHP has a built-in mail() function to send emails from a website. To enhance the functionality of this function, we need to make some changes to the message body in order to send attachments in an email from a website.

bool mail($to_email, $subject, $message, $headers, $parameters);
  1. $to_email: The email address to which the email will be sent.
  2. $subject: The subject of the email.
  3. $message: The message body of the email, either plain text or HTML.
  4. $headers: Headers of email like From, CC, BCC and Reply-To.
  5. $parameters: The additional parameters that can be used for the command-line tool sending the email.

We will create an HTML form with To, From, Subject and message fields to send an email. We will also add a file input field to upload files and send them as attachments in the email. Files that are going to be created for this post are:

  1. index.php: An HTML page containing the email form with an input file field.
  2. send-email.php: The PHP script to send an email with attachments.
  3. javascript.js: The JavaScript file to initialize the TinyMCE editor on the textarea field.
  4. style.css: The CSS stylesheet for the HTML page and form.

Create an HTML Form to Send Email

Create an HTML page with a form containing the needed form to send an email. The following fields will be added to the form:

  • An email field to enter the email address "To" to which the email will be sent.
  • An email field to enter the email address for the "From" address.
  • A text field for the subject of the email.
  • An input file field with a multiple attribute to allow multiple file uploads.
  • A textarea field with the TinyMCE editor to support rich text HTML.
  • The form must have the attribute enctype=multipart/form-data for file uploads.

index.php

<?php
if (!session_id()) {
session_start();
}
?>
<!DOCTYPE html>
<html>
<head>
<title>Send an Email with Attachment in PHP - Demo</title>
<meta content="text/html; charset=UTF-8" http-equiv="Content-Type"/>
<meta content="width=device-width, initial-scale=1, maximum-scale=1" name="viewport"/>
<link rel="stylesheet" href="css/style.css"/>
<script src="js/jquery-3.1.1.min.js"></script>
<script src="plugins/tinymce/js/tinymce/tinymce.min.js"></script>
<script src="js/javascript.js" type="text/javascript"></script>
</head>
<body>
<section class="section py-4">
<div class="container">
<?php if (isset($_SESSION['message'])) { ?>
<div class="alert alert-<?= $_SESSION['status']; ?>">
<?= $_SESSION['message']; ?>
</div>
<?php
unset($_SESSION['message'], $_SESSION['status']);
} ?>
<form action="send-email.php" method="POST" enctype="multipart/form-data" class="email-form">
<div class="mb-4">
<label class="inline-block mb-1">To email address: <span class="text-red">*</span></label>
<input type="email" name="from" class="form-control" required="required"
placeholder="Email address..."/>
</div>
<div class="mb-4">
<label class="inline-block mb-1">From email address: <span class="text-red">*</span></label>
<input type="email" name="to" class="form-control" required="required" placeholder="Email address..."/>
</div>
<div class="mb-4">
<label class="inline-block mb-1">Subject: <span class="text-red">*</span></label>
<input type="text" name="subject" class="form-control" required="required" placeholder="Subject..."/>
</div>

<div class="mb-4">
<label class="inline-block mb-1">Attach files</label>
<input type="file" name="attachments[]" class="form-control" multiple="multiple"/>
</div>
<div class="mb-4">
<label class="inline-block mb-1">Email message: <span class="text-red">*</span></label>
<textarea name="message" class="form-control tinymce" required="required"
placeholder="Message..."></textarea>
</div>

<div class="mb-4">
<button type="submit" class="btn btn-blue">Send</button>
</div>
</form>
</div>
</section>
</body>
</html>
 

Send an Email with an Attachment (PHP Script)

Create a script to add files as attachments in a message and send the email using the PHP mail() function. The logical flow is to set the multipart/mixed content type in the header, start a boundary for the message body and for each file start a separate boundary. The following are the steps to send attachments with email in PHP by extending the message body using boundaries and using the built-in mail function of PHP:

  • Start a session to store the message and status of the message.
  • Sanitize the $_POST array and store it in a variable.
  • Create a unique ID for the boundary.
  • Set headers for the email including MIME-Version, Content-Type, From and Reply-To.
  • Start a boundary for email message with Content-Type: text/html, charset=UTF-8, Content-Transfer-Encoding: Quot-Printed and finally add the message sent in the form submission.
  • Loop through each uploaded file and start a boundary for each file.
    • Add Content-Type: application/octet-stream; filename=$file_name to the message.
    • Add Content-Description: $file_name to the message.
    • Add Content-Transfer-Encoding: base64 to the message.
    • Add Content-Disposition: attachment; filename=$file_name to the message.
    • Add the base64-encoded content of the uploaded file to the email message.
  • Close the boundary of the entire message with the $uid variable.
  • Send the email using the PHP mail function.
  • Set the message and status in the session based on whether the email was sent or not.
  • Redirect the user to the HTML form page after the email is sent, regardless of the success or failure of delivery.

send-email.php

<?php
if (!session_id()) {
session_start();
}

$post = filter_input_array(INPUT_POST, [
'to' => FILTER_SANITIZE_EMAIL,
'from' => FILTER_SANITIZE_EMAIL,
'subject' => FILTER_DEFAULT,
'message' => FILTER_DEFAULT,
]);

$uid = md5(uniqid(time()));

// Set headers for email
$headers = [
'MIME-Version' => '1.0',
'Content-Type' => sprintf("%s boundary=\"%s\"", 'multipart/mixed;', $uid),
'From' => sprintf('<%s>', $post['from']),
'Reply-To' => sprintf('<%s>', $post['from']),
];

// Add boundary for email message
$message = sprintf("--%s\r\n", $uid);
$message .= sprintf("Content-type: %s\r\n", 'text/html; charset=UtF-8');
$message .= sprintf("Content-Transfer-Encoding: %s\r\n\r\n", 'Quot-Printed');
$message .= sprintf("%s\r\n\r\n", stripcslashes($post['message']));

if (!empty($_FILES)) {
for ($i = 0; $i < count($_FILES['attachments']['name']); $i++) {
// If there is an error in uploaded file then continue and skip this file
if ($_FILES['attachments']['error'][$i] > 0) {
continue;
}

// Store file name in a variable
$file_name = $_FILES['attachments']['name'][$i];

// Get the file content of current file in loop
$file_content = file_get_contents($_FILES['attachments']['tmp_name'][$i]);

// Add boundary for each attachment file
$message .= sprintf("--%s\r\n", $uid);
$message .= sprintf("Content-Type: application/octet-stream; name=\"%s\"\r\n", $file_name);
$message .= sprintf("Content-Description: %s\r\n", $file_name);
$message .= sprintf("Content-Transfer-Encoding: %s\r\n", 'base64');
$message .= sprintf("Content-Disposition: attachment; filename=\"%s\"\r\n\r\n", $file_name);
$message .= sprintf("%s\r\n\r\n", chunk_split(base64_encode($file_content)));
}
}

// Close over all message boundary
$message .= sprintf("--%s--", $uid);

if (mail($post['to'], $post['subject'], $message, $headers)) {
$_SESSION['message'] = 'Email has been successfully sent';
$_SESSION['status'] = 'green';
} else {
$_SESSION['message'] = 'Failed to send email';
$_SESSION['red'] = 'red';
}

header('Location: ' . $_SERVER['HTTP_REFERER']);
exit;
 

Enable TinyMCE Editor on TextArea

Add JavaScript code to initialize the TinyMCE editor to support rich HTML text.

javascript.js

$(document).ready(function () {
tinymce.init({
branding: false,
selector: '.tinymce',
height: '350',
required: true,
showPreview: true,
setup: function (editor) {
editor.on('change', function (e) {
editor.save();
});
}
});
});

Add CSS Styles

Add CSS rules for the entire HTML page and email form fields.

style.css

* {
box-sizing: border-box;
}
html,body {
margin: 0;
padding: 0;
}
body {
background-color: #f6f6f6;
font-family: "Segoe UI", "Roboto", "Helvetica", sans-serif;
font-size: 15px;
font-weight: normal;
font-style: normal;
}
.container {
max-width: 1024px;
margin: 0 auto;
padding-left: 15px;
padding-right: 15px;
}
.py-4 {
padding-top: 1rem;
padding-bottom: 1rem;
}
.my-1, .mb-1 {
margin-bottom: .25rem;
}
.my-4, .mb-4 {
margin-bottom: 1rem;
}
.inline-block {
display: inline-block;
}
.text-red {
color: #e65442;
}
.alert {
position: relative;
padding: .75rem 1.25rem;
margin-bottom: 1rem;
transition:opacity 0.5s;
}
.alert-green {
background-color: #319764;
border: 1px solid #248A57;
color: #ffffff;
}
.alert-red {
background-color: #e65442;
border: 1px solid #d94735;
color: #ffffff;
}
.form-control {
display: block;
width: 100%;
padding: .375rem .75rem;
font-size: 1rem;
font-weight: 400;
line-height: 1.5;
color: #1c2528;
background-color: #ffffff;
background-clip: padding-box;
border: 1px solid #d1d2d3;
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
}
.form-control:focus {
border-color: #00c0ef;
outline: 0;
}
.btn {
display: inline-block;
padding: .375rem .75rem;
cursor: pointer;
font-size: inherit;
}
.btn-blue {
background-color: #0369a1;
border: 1px solid #0369a1;
color: #ffffff;
}
.btn-blue:hover {
background-color: #005D95;
}

We just demonstrated how to send emails with attachments in PHP, allowing different file types to be added as attachments. With the code snippets in this post, we are now able to send an email with attachments from a PHP web application. The script can be further extended to meet the specific requirements of an application.