Reader Stacks

Sending Email in Laravel: Gmail, SendGrid, Sendmail, and Attachments

Laravel's Mail facade works the same regardless of the underlying transport — the differences are all in the .env configuration, covered here for the most common providers.

Sending Email in Laravel: Gmail, SendGrid, Sendmail, and Attachments

Laravel's mail system is transport-agnostic — you write the same Mail::to()->send() code regardless of whether it's actually going out through Gmail's SMTP servers, SendGrid's API, or a local sendmail binary. The differences all live in your .env configuration.

Sending through Gmail SMTP

MAIL_MAILER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=you@gmail.com
MAIL_PASSWORD=your-app-password
MAIL_ENCRYPTION=tls

Gmail requires an App Password here, not your regular account password — generate one from your Google Account's security settings (this requires 2-factor authentication to be enabled first). Using your actual login password will fail authentication.

Sending through a generic SMTP server or local sendmail

MAIL_MAILER=smtp
MAIL_HOST=mail.yourdomain.com
MAIL_PORT=587
MAIL_USERNAME=noreply@yourdomain.com
MAIL_PASSWORD=your-password
MAIL_ENCRYPTION=tls

// or, using the local sendmail binary instead of SMTP
MAIL_MAILER=sendmail
MAIL_SENDMAIL_PATH="/usr/sbin/sendmail -bs"

sendmail relies on a mail transfer agent already configured on the server itself — reasonable on a traditional VPS with Postfix or similar installed, but generally not available (or reliable for actual deliverability) on typical shared hosting or serverless platforms.

Sending through SendGrid

MAIL_MAILER=smtp
MAIL_HOST=smtp.sendgrid.net
MAIL_PORT=587
MAIL_USERNAME=apikey
MAIL_PASSWORD=your-sendgrid-api-key
MAIL_ENCRYPTION=tls

SendGrid's SMTP username is literally the string apikey — the actual API key goes in the password field. A dedicated transactional email provider like SendGrid also generally offers better deliverability and analytics than sending directly through Gmail or a generic SMTP host at any real volume.

Sending to multiple recipients, with CC

Mail::to(['first@example.com', 'second@example.com'])
    ->cc('manager@example.com')
    ->send(new OrderShipped($order));

Sending an email with an attachment

class InvoiceMail extends Mailable
{
    public function build()
    {
        return $this->view('emails.invoice')
            ->attach(storage_path('app/invoices/invoice-123.pdf'), [
                'as' => 'invoice.pdf',
                'mime' => 'application/pdf',
            ]);
    }
}

The same attach() method works for PDFs, images, or Word documents — Laravel doesn't need a different API per file type, only the correct mime value if you want it set explicitly rather than guessed from the file extension.

Choosing a provider

Gmail SMTP is fine for low-volume personal or small-project sending; a generic SMTP host works when you already have one configured; a dedicated provider like SendGrid (or similar services) is the more reliable choice once an application sends enough transactional email that deliverability and bounce handling genuinely matter.