Send emails with Symfony

In this quickstart, you'll learn how to send transactional emails from your Symfony 6 or 7 app with Sidemail. You'll set up the SDK, send your first email, and see examples for common use cases like welcome emails, password resets, and scheduled reports.

Before you start

  1. Create a Sidemail account → get your API key
  2. Add a sending domain → set up your domain for sending

1. Install

composer require sidemail/sidemail

2. Add your API key

Add your Sidemail API key to .env:

SIDEMAIL_API_KEY=your-api-key

3. Configure the service

Register the Sidemail client as a service in config/services.yaml. The SDK reads SIDEMAIL_API_KEY automatically from env.

# config/services.yaml
services:
  # ... other services

  Sidemail\Sidemail:
    autowire: true

4. Send a welcome email with Symfony

Inject Sidemail\Sidemail into your controller (e.g. src/Controller/RegistrationController.php).

namespace App\Controller;

use Sidemail\Sidemail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class RegistrationController extends AbstractController
{
    #[Route('/register', methods: ['POST'])]
    public function register(Sidemail $sidemail): Response
    {
        // ... create user ...

        $sidemail->sendEmail([
            'toAddress'     => '[email protected]',
            'fromAddress'   => '[email protected]',
            'fromName'      => 'Your App',
            'templateName'  => 'Welcome',
            'templateProps' => ['firstName' => 'Alex'],
        ]);

        return new Response('User registered!');
    }
}

5. Send a password reset email with Symfony

// src/Controller/SecurityController.php

use Sidemail\Sidemail;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class SecurityController extends AbstractController
{
    #[Route('/reset-password', methods: ['POST'])]
    public function requestReset(Request $request, Sidemail $sidemail): Response
    {
        // In a real app, use Symfony Forms for validation, find user, generate token ...
        $email = $request->request->get('email');
        $token = 'secure-password-reset-token';

        $sidemail->sendEmail([
            'toAddress'     => $email,
            'fromAddress'   => '[email protected]',
            'fromName'      => 'Your App',
            'templateName'  => 'Password Reset',
            'templateProps' => [
                'actionUrl' => 'https://myapp.com/reset/' . $token,
            ],
        ]);

        return new Response('Reset link sent!');
    }
}

6. Send a weekly report (Cron Task) with Symfony

Create a console command to send emails on a schedule.

// src/Command/SendWeeklyReportCommand.php
namespace App\Command;

use Sidemail\Sidemail;
use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

#[AsCommand(name: 'app:send-weekly-report')]
class SendWeeklyReportCommand extends Command
{
    public function __construct(
        private Sidemail $sidemail
    ) {
        parent::__construct();
    }

    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        // In a real app, you would calculate this from the database
        $newSignups = 150;
        $chartData = [100, 200, 300, 400, 200, 300, 200, 500];

        $this->sidemail->sendEmail([
            'toAddress'     => '[email protected]',
            'fromAddress'   => '[email protected]',
            'fromName'      => 'My App',
            'templateName'  => 'Weekly Report',
            'templateProps' => [
                'signups' => $newSignups,
                'chart'   => $chartData,
            ],
        ]);

        return Command::SUCCESS;
    }
}

You can now run this command manually or schedule it with cron:

# Run every Monday at 8:00 AM
0 8 * * 1 bin/console app:send-weekly-report

7. Send email via Event Subscriber with Symfony

Decouple email sending from your controllers by using an event subscriber.

// src/EventSubscriber/UserRegisteredSubscriber.php
namespace App\EventSubscriber;

use App\Event\UserRegisteredEvent;
use Sidemail\Sidemail;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class UserRegisteredSubscriber implements EventSubscriberInterface
{
    public function __construct(
        private Sidemail $sidemail
    ) {}

    public static function getSubscribedEvents(): array
    {
        return [
            UserRegisteredEvent::class => 'onUserRegistered',
        ];
    }

    public function onUserRegistered(UserRegisteredEvent $event): void
    {
        $this->sidemail->sendEmail([
            'toAddress'    => $event->getUser()->getEmail(),
            'fromAddress'  => '[email protected]',
            'fromName'     => 'My App',
            'templateName' => 'Welcome',
        ]);
    }
}

8. Send HTML email (with Twig)

Use $this->renderView() to generate HTML from a Twig template.

// src/Controller/InvoiceController.php

public function sendInvoice(Sidemail $sidemail): Response
{
    $html = $this->renderView('emails/invoice.html.twig', [
        'amount' => 99,
    ]);

    $sidemail->sendEmail([
        'toAddress'   => '[email protected]',
        'fromAddress' => '[email protected]',
        'fromName'    => 'Your App',
        'subject'     => 'Your Invoice',
        'html'        => $html,
    ]);

    return new Response('Invoice sent!');
}

9. Send Markdown email

Store your markdown content in a file (e.g. templates/emails/welcome.md) and load it.

$markdown = file_get_contents($this->getParameter('kernel.project_dir') . '/templates/emails/welcome.md');

$this->sidemail->sendEmail([
    'toAddress'     => '[email protected]',
    'fromAddress'   => '[email protected]',
    'fromName'      => 'Your App',
    'subject'       => 'Testing markdown emails 😊',
    'markdown'      => $markdown,
    'templateProps' => [
        'name' => 'John',
        'link' => 'https://example.com',
    ],
]);

10. Send plain text email

$this->sidemail->sendEmail([
    'toAddress'   => '[email protected]',
    'fromAddress' => '[email protected]',
    'fromName'    => 'Your App',
    'subject'     => 'Hello',
    'text'        => 'Hello! 👋',
]);

11. Schedule email

Send email later. Set scheduledAt to an ISO date string.

$this->sidemail->sendEmail([
    'toAddress'     => '[email protected]',
    'fromAddress'   => '[email protected]',
    'fromName'      => 'Your App',
    'templateName'  => 'Welcome',
    'templateProps' => ['firstName' => 'Alex'],
    'scheduledAt'   => (new \DateTimeImmutable('+1 hour'))->format(\DateTimeInterface::ATOM),
]);

12. Send with attachment

Use the Sidemail::fileToAttachment helper to attach files.

use Sidemail\Sidemail;

$pdfData = file_get_contents($this->getParameter('kernel.project_dir') . '/var/invoice.pdf');
$attachment = Sidemail::fileToAttachment('invoice.pdf', $pdfData);

$this->sidemail->sendEmail([
    'toAddress'   => '[email protected]',
    'fromAddress' => '[email protected]',
    'fromName'    => 'Your App',
    'subject'     => 'Your invoice',
    'text'        => 'See attached.',
    'attachments' => [$attachment],
]);

13. Handle errors

use Sidemail\SidemailException;
use Psr\Log\LoggerInterface;

class EmailController extends AbstractController
{
    public function send(Sidemail $sidemail, LoggerInterface $logger): Response
    {
        try {
            $sidemail->sendEmail([/* ... */]);
        } catch (SidemailException $e) {
            $logger->error('Sidemail error', [
                'message'    => $e->getMessage(),
                'httpStatus' => $e->getHttpStatus(),
                'errorCode'  => $e->getErrorCode(),
            ]);
            return new Response('Error sending email', 500);
        }

        return new Response('Email sent!');
    }
}