Back to blog
PHPEmailTutorialLaravel

How to Send Email in PHP (SMTP + API)

Send email from PHP using mail(), PHPMailer, or an email API. Complete guide with code examples for Laravel, plain PHP, attachments, HTML email, and local testing.

SendPigeon TeamMarch 27, 20266 min read

To send email in PHP, use an email API (one HTTP call via SDK) or PHPMailer with SMTP. Avoid PHP's built-in mail() function — it has no authentication, no TLS, and poor deliverability.

This guide covers three approaches with code examples for plain PHP and Laravel.

TL;DR

Email API (recommended):

use SendPigeon\Client;
$client = new Client('sp_live_xxx');
$client->send(to: 'user@example.com', from: 'hello@yourdomain.com',
    subject: 'Hello', html: '<h1>Hello!</h1>');

PHPMailer (SMTP):

$mail = new PHPMailer(true);
$mail->isSMTP();
$mail->Host = 'smtp.yourprovider.com';
$mail->send();

Avoid: mail() — no auth, no TLS, lands in spam.


Method 1: Email API (Recommended)

An email API handles SMTP connections, DKIM signing, bounce processing, and retries. One HTTP call sends the email.

Install

composer require sendpigeon/sdk

Send an email

<?php
require 'vendor/autoload.php';

use SendPigeon\Client;

$client = new Client(getenv('SENDPIGEON_API_KEY'));

try {
    $response = $client->send(
        to: 'user@example.com',
        from: 'hello@yourdomain.com',
        subject: 'Your order shipped',
        html: '<h1>Your order has shipped</h1><p>Track it here.</p>',
    );

    echo "Sent: " . $response->id;
} catch (\SendPigeon\Exceptions\ApiException $e) {
    echo "Failed: " . $e->getMessage();
}

No SMTP configuration, no MIME headers, no connection management.

Send with attachments

$response = $client->send(
    to: 'customer@example.com',
    from: 'billing@yourdomain.com',
    subject: 'Your invoice',
    html: '<p>Invoice attached.</p>',
    attachments: [
        [
            'filename' => 'invoice.pdf',
            'content' => base64_encode(file_get_contents('invoice.pdf')),
        ],
    ],
);

Method 2: PHPMailer (SMTP)

PHPMailer is the most popular PHP email library. It handles SMTP connections, TLS, authentication, and MIME message building.

Install

composer require phpmailer/phpmailer

Send an HTML email

<?php
require 'vendor/autoload.php';

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

$mail = new PHPMailer(true);

try {
    // SMTP configuration
    $mail->isSMTP();
    $mail->Host       = 'smtp.yourprovider.com';
    $mail->SMTPAuth   = true;
    $mail->Username   = getenv('SMTP_USER');
    $mail->Password   = getenv('SMTP_PASS');
    $mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS;
    $mail->Port       = 587;

    // Email content
    $mail->setFrom('hello@yourdomain.com', 'Your App');
    $mail->addAddress('user@example.com');
    $mail->isHTML(true);
    $mail->Subject = 'Your order shipped';
    $mail->Body    = '<h1>Your order has shipped</h1><p>Track it here.</p>';
    $mail->AltBody = 'Your order has shipped. Track it here.';

    $mail->send();
    echo 'Email sent';
} catch (Exception $e) {
    echo "Failed: {$mail->ErrorInfo}";
}

Send with attachments

$mail->addAttachment('invoice.pdf');                 // From file path
$mail->addAttachment('data.csv', 'report.csv');      // With custom filename
$mail->addStringAttachment($pdfContent, 'invoice.pdf'); // From string

SMTP Provider Configuration

Common SMTP settings for PHPMailer:

ProviderHostPortEncryption
SendPigeonsmtp.sendpigeon.dev587STARTTLS
Gmailsmtp.gmail.com587STARTTLS
AWS SESemail-smtp.{region}.amazonaws.com587STARTTLS
SendGridsmtp.sendgrid.net587STARTTLS
Mailgunsmtp.mailgun.org587STARTTLS

Gmail limits you to ~500 emails/day and requires an App Password. For production email, use a dedicated email service.


Method 3: PHP mail() (Not Recommended)

PHP's built-in mail() function exists but has significant limitations:

// Works but don't use this in production
mail(
    'user@example.com',
    'Subject',
    'Hello!',
    "From: hello@yourdomain.com\r\n"
);

Why to avoid it:

  • No SMTP authentication — sends through local sendmail/postfix
  • No TLS encryption
  • No DKIM signing
  • No delivery tracking or error details
  • Emails frequently land in spam
  • Behavior varies across hosting environments

Use PHPMailer or an email API instead.


Send Email from Laravel

Laravel has built-in email support with SMTP, Mailables, and notifications.

Configure SMTP in .env

MAIL_MAILER=smtp
MAIL_HOST=smtp.sendpigeon.dev
MAIL_PORT=587
MAIL_USERNAME="${SENDPIGEON_API_KEY}"
MAIL_PASSWORD="${SENDPIGEON_API_KEY}"
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=hello@yourdomain.com
MAIL_FROM_NAME="${APP_NAME}"

Send with Mail facade

use Illuminate\Support\Facades\Mail;

Mail::raw('Thanks for signing up!', function ($message) {
    $message->to('user@example.com')
            ->subject('Welcome!');
});

Create a Mailable

php artisan make:mail WelcomeEmail
// app/Mail/WelcomeEmail.php
namespace App\Mail;

use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;

class WelcomeEmail extends Mailable
{
    public function __construct(public string $userName) {}

    public function envelope(): Envelope
    {
        return new Envelope(subject: "Welcome, {$this->userName}!");
    }

    public function content(): Content
    {
        return new Content(
            view: 'emails.welcome',
            with: ['name' => $this->userName],
        );
    }
}
// In your controller
Mail::to($user->email)->send(new WelcomeEmail($user->name));

Queue emails in Laravel

Laravel's queue system works with email out of the box:

// Send in background (queued)
Mail::to($user->email)->queue(new WelcomeEmail($user->name));

// Delay sending
Mail::to($user->email)->later(now()->addMinutes(5), new WelcomeEmail($user->name));

Configure your queue driver in .env:

QUEUE_CONNECTION=database  # or redis, sqs

API vs PHPMailer vs mail()

Email APIPHPMailermail()
Installcomposer require sendpigeon/sdkcomposer require phpmailer/phpmailerBuilt-in
SMTP authN/A (uses HTTP)YesNo
TLSAlways (HTTPS)YesNo
DKIMAutomaticManualNo
Bounce handlingAutomaticManualNone
TrackingOpens, clicks, statusNoneNone
Error handlingTyped exceptionsException with detailsReturns true/false
ServerlessWorks everywhereWorks everywhereMay not work

Test Locally

Catch emails locally during development:

npx @sendpigeon-sdk/cli dev

Configure PHPMailer to use the local server:

$mail->Host = 'localhost';
$mail->Port = 4125;
$mail->SMTPAuth = false;
$mail->SMTPSecure = false;

View captured emails at localhost:4100. See the local email testing guide for full setup.


FAQ

What is the best way to send email in PHP?

Use an email API for production applications. For scripts or existing codebases, PHPMailer with SMTP is solid. Avoid mail() — it has no authentication and poor deliverability.

Why shouldn't I use PHP mail()?

mail() sends through the local MTA without SMTP authentication, TLS, or DKIM signing. Emails frequently land in spam. Use PHPMailer or an email API instead.

How do I send email from Laravel?

Configure SMTP in your .env file and use Mail::send() or create Mailables. Laravel also supports queued emails with Mail::queue(). See the Laravel section above.

How do I send HTML email in PHP?

With PHPMailer, call $mail->isHTML(true) and set $mail->Body to your HTML. Always set $mail->AltBody as a plain text fallback. With an email API, pass the HTML string directly.

Can I use Composer packages for sending email?

Yes. The SendPigeon SDK (composer require sendpigeon/sdk) and PHPMailer (composer require phpmailer/phpmailer) are both installed via Composer. Both are well-maintained and widely used.


Next Steps