How to Send Emails in PHP

On January 26, 2024
12min read
Viktoriia Ivanenko Technical Content Writer @ Mailtrap

Technologies advance – so does the world every day. But some things stay forever. Like sending emails with PHP. You might be skeptical and thinking even in 2024? Yes, even in 2024. W3Techs reports that, as of January 2024, “PHP is used by 76.5% of all the websites whose server-side programming language we know.” 

Toy Story Robot says "PHP everywhere"

That said, let’s check out this tutorial that will help you send emails from PHP today.

Send mail from PHP: three important things that you need to know right away

One, there is a built-in PHP mail() function and it is quite simple.

Two, although PHP’s built-in mail function () is very simple, it provides limited functionality for sending emails. You won’t be able to add attachments to your email, and building a beautiful HTML template with embedded images will be a tricky task as well. 

Three, the PHP mail function () sends emails from your website, which may cause issues with deliverability due to security concerns such as suspicion of spam and blacklisting. PHP mail() also does not usually allow you to send mail using an SMTP server externally, and it does not support SMTP authentication.

What options do you have to send emails in PHP?

There are four popular ones.

  1. A built-in PHP mail() function;
  2. PHPMailer;
  3. Symfony Mailer;
  4. Third-party email sending services like Mailtrap, Sendgrid, Mailgun, etc.

We’ll go step-by-step through all of them.

PHP built-in mail function () 

The PHP function mail() is a built-in function for sending emails in PHP, but it has some limitations and potential drawbacks that make it less popular than other email sending options.

Here are some reasons why mail() is not commonly used for sending emails in PHP:

– Deliverability issues: The mail() function relies on the local mail server configuration, which can result in emails being flagged as spam or rejected by some email providers. This can cause deliverability issues and make it difficult to ensure that emails are being delivered to recipients.

– Lack of features: The mail() function does not support many advanced features such as SMTP authentication, email tracking, and attachments. This can limit the functionality of your email sending application.

– Security concerns: The mail() function can be vulnerable to email injection attacks, where an attacker can inject additional headers into the email message, potentially compromising the security of the email system.

While the mail() function can be a simple and lightweight option for sending emails in some cases, it is not recommended for production use and is generally considered less robust than other email sending options available in PHP.

Mail() is a wrapper on top of the sendmail utility, so sendmail has to be installed in the system first.

Here’s what you can do with PHP built-in mail function(): 

  • create simple HTML/text messages without attachments and images
  • send them to one or several recipients
  • include additional headers to the message
  • add additional parameters to the `sendmail` command

Keep in mind that when you send emails with mail(), you may come across some grave deliverability issues. The messages dispatched will not benefit from the SPF and DKIM setup on your domain, therefore, the messages will likely be treated as spam by the receiving MTA (Mail Transfer Agent). Thus, the overall deliverability of email messages sent via PHP mail () is not guaranteed. Moreover, you won’t receive bounce back messages if there is a delivery failure.

If you are still committed to the PHP built-in mail function() and are ready to accept the challenge, let’s take a look at the basic PHP script syntax and its main parameters. 

Syntax and parameters

The PHP mail syntax is pretty simple:

<?php
mail($to,$subject,$message,[$headers],[$parameters]);
?>

It uses the following parameters: 

  • “$to” = your message recipient(s). The email address format may be user@example.com or User <user@example.com>. In general, it needs to comply with RFC 2822. It is mandatory.
  • “$subject” = your message’s subject. 
  • “$message” = the body of your message. Lines should be separated with a CRLF (\r\n). Each line should not exceed 70 characters.
  • “[$headers]” = the mandatory one is the “from” header: it must be specified, otherwise, you will receive an error message like Warning: mail(): “sendmail_from” not set in php.ini or custom “From:” header missing.

The additional headers indicate other recipients or copies of your message like CC or BCC. They can be an array where the key is a header name and the value is a header value. Or they can be a string. In this case, headers should be separated with a CRLF (\r\n).

  • [$parameters] = for specifying the additional parameters defined in the sendmail_path configuration setting.

For more details and additional parameters, refer to the PHP documentation

Sending HTML email using PHP mail() function

The body of the message can be written in HTML. However, as we’ve mentioned above, it should be simple. 

In the PHP mail function(), the HTML message part will look like this:

// Message
$message = '
<html>
<head>
  <title>Review Request Reminder</title>
</head>
<body>
  <p>Here are the cases requiring your review in December:</p>
  <table>
    <tr>
      <th>Case title</th><th>Category</th><th>Status</th><th>Due date</th>
    </tr>
    <tr>
      <td>Case 1</td><td>Development</td><td>pending</td><td>Dec-20</td>
    </tr>
    <tr>
      <td>Case 1</td><td>DevOps</td><td>pending</td><td>Dec-21</td>
    </tr>
  </table>
</body>
</html>
';

It’s important to remember that to send HTML mail, you need to set the Content-type header:

$headers[‘MIME-Version’] = 'MIME-Version: 1.0';
$headers[‘Content-type’] = text/html; charset=iso-8859-1';

Simple Transmission Protocol (SMTP)

Where do I specify the SMTP settings? This is a fair question. Go to the PHP file installation folder and configure them in the php.ini file. But this will only work for localhost or XAMPP-like solutions, because, as we have already mentioned, the PHP mail() function does not support SMTP authentication and doesn’t allow sending messages via external servers. 

To send mail without SMTP, you could also refer to a third party-service like Mailtrap, SendGrid, or Mailgun. 

Sending multiple emails

To send your message to multiple recipients, specify their email addresses in the “$to” =  parameter separating them with a comma(-s).  

It’s the only suitable method with a native mail() function. If you need to send a large volume of messages in a loop, try an external mailing package like Symfony Mailer. Or the third-party solution.

How to send emails using PHP via the contact form?

There are also a couple of ways to do this. And this topic needs a special tutorial. Whether you run a WordPress website or need a simple contact form, check out this encoding for a PHP contact form with Google reCaptcha. 

We explain how it works in detail, plus we go through many other ways to create contact forms in PHP in our special guide on PHP code to send email from a contact form. Tune in.

<?php

use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;

require 'vendor/autoload.php';

$errors = [];
$errorMessage = '';
$successMessage = '';
$siteKey = ''; // reCAPTCHA site key
$secret = ''; // reCAPTCHA secret key

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = sanitizeInput($_POST['name']);
    $email = sanitizeInput($_POST['email']);
    $message = sanitizeInput($_POST['message']);
    $recaptchaResponse = sanitizeInput($_POST['g-recaptcha-response']);

  $recaptchaUrl = "https://www.google.com/recaptcha/api/siteverify?secret={$secret}&response={$recaptchaResponse}";
  $verify = json_decode(file_get_contents($recaptchaUrl));
  
  if (!$verify->success) {
    $errors[] = 'Recaptcha failed';
  }
  if (empty($name)) {
    $errors[] = 'Name is empty';
  }
  if (empty($email)) {
    $errors[] = 'Email is empty';
  }  else if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
    $errors[] = 'Email is invalid';
  }
  if (empty($message)) {
    $errors[] = 'Message is empty';
  }

  if (!empty($errors)) {
    $allErrors = join('<br/>', $errors);
    $errorMessage = "<p style='color: red;'>{$allErrors}</p>";
  } else {
    $toEmail = 'mailtrap.club@gmail.com';
    $emailSubject = 'New email from your contaсt form';

      // Create a new PHPMailer instance
        $mail = new PHPMailer(true);
        try {
            // Configure the PHPMailer instance
            $mail->isSMTP();
            $mail->Host = 'live.smtp.mailtrap.io';
            $mail->SMTPAuth = true;
            $mail->Username = '';
            $mail->Password = '';
            $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
            $mail->Port = 587;

            // Set the sender, recipient, subject, and body of the message
            $mail->setFrom($email);
            $mail->addAddress($toEmail);
            $mail->Subject = $emailSubject;
            $mail->isHTML(true);
            $mail->Body = "<p>Name: {$name}</p><p>Email: {$email}</p><p>Message: {$message}</p>";

            // Send the message
            $mail->send();

            $successMessage = "<p style='color: green;'>Thank you for contacting us :)</p>";
        } catch (Exception $e) {
      $errorMessage = "<p style='color: red;'>Oops, something went wrong. Please try again later</p>";
    }
  }
}

function sanitizeInput($input) {
   $input = trim($input);
   $input = stripslashes($input);
   $input = htmlspecialchars($input, ENT_QUOTES, 'UTF-8');
   return $input;
}

?>

<html>
  <body>
    <script src="https://www.google.com/recaptcha/api.js" async defer></script>
    <form action="/"method="post" id="contact-form">
      <h2>Contact us</h2>
      <?php echo((!empty($errorMessage)) ? $errorMessage : '') ?>
      <?php echo((!empty($successMessage)) ? $successMessage : '') ?>
      <p>
        <label>First Name:</label>
        <input name="name" type="text" required />
      </p>
      <p>
        <label>Email Address:</label>
        <input style="cursor: pointer;" name="email" type="email" required />
      </p>
      <p>
        <label>Message:</label>
        <textarea name="message" required></textarea>
      </p>
      <p>
        <button
        class="g-recaptcha"
        type="submit"
        data-sitekey="<?php echo $siteKey ?>"
        data-callback='onRecaptchaSuccess'
        >
          Submit
        </button>
      </p>
    </form>

    <script>
    function onRecaptchaSuccess() {
      document.getElementById('contact-form').submit();
    }
    </script>
  </body>
</html>

How to send emails with PHPMailer?

PHPMailer is the classic and the most popular email sending library for PHP. It deserves a separate article and a tutorial. To get a detailed overview of the PHP code in PHPMailer read our guide on how to send emails using PHPMailer.

What you can do with PHPMailer

  • create complex HTML/multipart templates
  • add attachments and embedded images
  • send email from authenticated SMTP. 

PHPMailer is protected against header injection attacks and automatically validates emails. 

Now let’s send, say, a hotel booking confirmation with PHPMailer. The code requires the Symfony Mailer library to be installed through Composer (follow the manual for installation):

<?php
// Start with PHPMailer class
use PHPMailer\PHPMailer\PHPMailer;
require_once './vendor/autoload.php';
// create a new object
$mail = new PHPMailer();
// configure an SMTP
$mail->isSMTP();
$mail->Host = 'live.smtp.mailtrap.io';
$mail->SMTPAuth = true;
$mail->Username = 'api';
$mail->Password = '1a2b3c4d5e6f7g';
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
$mail->Port = 587;

$mail->setFrom('confirmation@hotel.com', 'Your Hotel');
$mail->addAddress('me@gmail.com', 'Me');
$mail->Subject = 'Thanks for choosing Our Hotel!';
// Set HTML 
$mail->isHTML(TRUE);
$mail->Body = '<html>Hi there, we are happy to <br>confirm your booking.</br> Please check the document in the attachment.</html>';
$mail->AltBody = 'Hi there, we are happy to confirm your booking. Please check the document in the attachment.';
// add attachment 
// just add the '/path/to/file.pdf'
$attachmentPath = './confirmations/yourbooking.pdf';
if (file_exists($attachmentPath)) {
    $mail->addAttachment($attachmentPath, 'yourbooking.pdf');
}

// send the message
if(!$mail->send()){
    echo 'Message could not be sent.';
    echo 'Mailer Error: ' . $mail->ErrorInfo;
} else {
    echo 'Message has been sent';
}

Pay attention: for this email message, we use the following piece of code

$mail->isSMTP();
$mail->Host = 'live.smtp.mailtrap.io';
$mail->SMTPAuth = true;
$mail->Username = 'api';
$mail->Password = '1a2b3c4d5e6f7g';
$mail->SMTPSecure = 'tls';
$mail->Port = 587;

to set the mail server, SMTP port, and enable email authentication. 

PHP mailing packages

As we have already mentioned, the native PHP mail() function is not designed for creating email templates and sending a large volume of emails. Moreover, it causes some serious deliverability issues. So we would recommend using some external mailing packages instead. For 2022, Pear:: Mail and Swift Mailer are not a thing anymore (as they are outdated now), so the obvious choice would be Symfony Mailer. 

Symfony Mailer & Mime components establish a solid system for creating and sending emails – complete with support for multipart messages, Twig integration, CSS inlining, file attachments, etc. We have created a step-by-step guide for sending emails in Symfony: from installation to transport setup, and creating and sending messages. Feel free to use it to your advantage. Do not hesitate to turn to the current version documentation for specific details.

Mind that here we show a standalone usage of this package, and it’s already integrated into Symfony and into the Laravel framework. So using it is simpler while working with the frameworks altogether.

<?php

use Symfony\Component\Mailer\Mailer; 
use Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport; 
use Symfony\Component\Mime\Email;

require_once './vendor/autoload.php';


$transport = (new EsmtpTransport('live.smtp.mailtrap.io', 587, false))
                ->setUsername('api')
                ->setPassword('1ca3b8a278cf32');

$mailer = new Mailer($transport); 

$email = (new Email())
            ->from('hello@example.com')
            ->to('you@example.com')
            ->subject('Time for Symfony Mailer!')
            ->text('Sending emails is fun again!')
            ->html('<p>See Twig integration for better HTML integration!</p>');

$mailer->send($email);    

Sending emails in PHP with third-party email services 

In case your application requires automated email sending and email analytics, it is always better to go for third-party email services. Why? It is faster, it is less labor and resource-consuming, and let’s be honest: it gives you more control over email infrastructure.

There are many third-party email services you can integrate your app with, such as Sendgrid, Mailgun, etc. But, the Mailtrap Email Delivery Platform might arguably be the one you actually need.

Using Mailtrap to send emails with PHP

If you’re looking for a reliable and hassle-free email sending service with PHP, you should probably consider Mailtrap Email Sending. It’s an Email API/SMTP service with high deliverability rates by design.

Dashboards with a clear snapshot of the state of your email infrastructure are always at hand for analytics. 

Statistics overview in Mailtrap Email Sending

Another advantage of Mailtrap Email Sending is our timely email deliverability alerts that give you greater control over your email infrastructure and domain authority. This means that if anything goes wrong with your deliverability unexpectedly, you get an alert with a color-coded table plus insights on where to inspect a deliverability issue. Yet, Mailtrap sends you regular weekly reports on your deliverability performance to keep you up to date with your email sending and deliverability performance.

Deliverability alerts in Mailtrap

Mailtrap Email Sending API integration for PHP

To start using the Mailtrap Email Sending API you first need to add and verify a domain as described in the video below: 

Once you’ve got that sorted, you can install the official Mailtrap PHP client via composer.

Running one of the following commands will get you started quickly:

# With symfony http client (recommend)
composer require railsware/mailtrap-php symfony/http-client nyholm/psr7

# Or with guzzle http client
composer require railsware/mailtrap-php guzzlehttp/guzzle php-http/guzzle7-adapter

Note: As the Mailtrap API Client uses PSR-18 client abstraction and is thus not hard coupled to any library that sends HTTP messages, it gives you the flexibility to choose which HTTP client you want to use.

Now, to finally send an email using the SDK, use the code snippet below:

<?php

use Mailtrap\Config;
use Mailtrap\EmailHeader\CategoryHeader;
use Mailtrap\EmailHeader\CustomVariableHeader;
use Mailtrap\Helper\ResponseHelper;
use Mailtrap\MailtrapClient;
use Symfony\Component\Mime\Address;
use Symfony\Component\Mime\Email;
use Symfony\Component\Mime\Header\UnstructuredHeader;

require __DIR__ . '/vendor/autoload.php';

// your API token from here https://mailtrap.io/api-tokens
$apiKey = getenv('MAILTRAP_API_KEY');
$mailtrap = new MailtrapClient(new Config($apiKey));

$email = (new Email())
    ->from(new Address('example@your-domain-here.com', 'Mailtrap Test'))
    ->replyTo(new Address('reply@your-domain-here.com'))
    ->to(new Address('email@example.com', 'Jon'))
    ->priority(Email::PRIORITY_HIGH)
    ->cc('mailtrapqa@example.com')
    ->addCc('staging@example.com')
    ->bcc('mailtrapdev@example.com')
    ->subject('Best practices of building HTML emails')
    ->text('Hey! Learn the best practices of building HTML emails and play with ready-to-go templates. Mailtrap’s Guide on How to Build HTML Email is live on our blog')
    ->html(
        '<html>
        <body>
        <p><br>Hey</br>
        Learn the best practices of building HTML emails and play with ready-to-go templates.</p>
        <p><a href="https://mailtrap.io/blog/build-html-email/">Mailtrap’s Guide on How to Build HTML Email</a> is live on our blog</p>
        <img src="cid:logo">
        </body>
    </html>'
    )
    ->embed(fopen('https://mailtrap.io/wp-content/uploads/2021/04/mailtrap-new-logo.svg', 'r'), 'logo', 'image/svg+xml')
    ;
    
    // Headers
    $email->getHeaders()
    ->addTextHeader('X-Message-Source', 'domain.com')
    ->add(new UnstructuredHeader('X-Mailer', 'Mailtrap PHP Client')) // the same as addTextHeader
    ;
    
    // Custom Variables
    $email->getHeaders()
    ->add(new CustomVariableHeader('user_id', '45982'))
    ->add(new CustomVariableHeader('batch_id', 'PSJ-12'))
    ;
    
    // Category (should be only one)
    $email->getHeaders()
    ->add(new CategoryHeader('Integration Test'))
    ;
    
try {
    $response = $mailtrap->sending()->emails()->send($email); // Email sending API (real)
    
    var_dump(ResponseHelper::toArray($response)); // body (array)
} catch (Exception $e) {
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}

// OR send email to the Mailtrap SANDBOX

try {
    $response = $mailtrap->sandbox()->emails()->send($email, 1000001); // Required second param -> inbox_id

    var_dump(ResponseHelper::toArray($response)); // body (array)
} catch (Exception $e) {
    echo 'Caught exception: ',  $e->getMessage(), "\n";
}

Note: By using the Composer autoloader in your application your dependencies will be automatically loaded.

Now you can start sending.

Try Sending Emails in PHP with Mailtrap for Free

Mailtrap Email Sending SMTP server configuration

Alternatively, you can use Mailtrap Email Sending SMTP Service instead of the API. Go to Sending Domains, click on the domain you want to send emails from, and open SMTP/API Settings tab. There, you’ll see your SMTP credentials, as well as sample configurations for various programming languages and frameworks.

A sample configuration for PHP will look like this:

<?php
// configure an SMTP
$mail->isSMTP();
$mail->Host = 'live.smtp.mailtrap.io';
$mail->SMTPAuth = true;
$mail->Username = 'api';
$mail->Password = '********2ff0';
$mail->SMTPSecure = 'tls';
$mail->Port = 587;

Common issues with PHP mails

We’ll cover only the basic issues here. In case you have a specific problem not mentioned here, refer to the PHP documentation or the sending service providers’ support.

Wrongly displayed characters

Let’s say the email doesn’t render German characters (umlauts) properly.

Then, you need to set the Content-Type and the Charset in the headers of the email. The Content-Type specifies the type of content in the email, and the Charset defines the character encoding used in the email. In this case, the Charset is set to UTF-8, which supports a wide range of characters and is a popular choice for character encoding:

<?php
$headers = 'Content-Type: text/plain; charset=utf-8' . "\r\n";
?>

Mostly, UTF-8 is your best choice.

Then, add the Content-Transfer-Encoding header, which specifies the encoding mechanism used to transfer data over the internet. Base64 is a popular encoding mechanism for email messages because it ensures that the data is transmitted safely across different email systems and servers:

<?php
$headers .= 'Content-Transfer-Encoding: base64' . "\r\n";
?>

Now, you can use both UTF-8 and Base64 to properly encode the subject line or the recipient name if they require specific characters.

<?php
$subject = '=?UTF-8?B?' . base64_encode('Test email with German Umlauts öäüß') . '?=';
$recipient = '=?UTF-8?B?' . base64_encode('Margret Müller') . '?= <recipient@domain.com>';
?>

And don’t forget to Base64 encode the email message too:

<?php
$message = base64_encode('This email contains German Umlauts öäüß.');
?>

Anyway, troubleshooting and testing need some special attention and in-depth analysis. Here, you can find out more about how to test emails sent from PHP.

Final considerations

In this article, we have described the basic PHP email sending principles, syntax, and parameters. We’ve also reviewed the main ways of sending emails with PHP: its built-in mail function. 

However, in many situations, you might consider using a third-party mail service integration like Mailtrap to save time, money, and effort.

Article by Viktoriia Ivanenko Technical Content Writer @ Mailtrap

Experienced content and marketing specialist: content creation for the blog and video channel, UX/UI copies, technical writing, app localizations, and SEO. Skilled in marketing strategies, video production and management, creating brand concepts, technical and marketing writing, and analytical skills. Strong information technology professional of 10+ years work experience with a background from The University of Edinburgh, UK and Clark University, USA.