Skip to content

[RFC][Mailer][FrameworkBundle] Add support for rate limited mailer transports #59985

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: 7.4
Choose a base branch
from

Conversation

fritzmg
Copy link
Contributor

@fritzmg fritzmg commented Mar 16, 2025

Q A
Branch? 7.4
Bug fix? no
New feature? yes
Deprecations? no
Issues
License MIT

Assume you have to use multiple SMTP servers in your application in order to be able to send emails on behalf of specific email accounts on a variety of hosting providers. Some of these hosting providers may impose limits on how many emails you can send per timeframe - especially in shared hosting environments. For example on Hetzner shared hostings the limit is 500 emails per hour, on webgo 50 emails per hour. Hetzner does not force this limit - but they may disable your account completely, if you break this rule. The same applies to services like sendgrid etc., where you will have certain limits.

Now, if you use symfony/messenger in order to send your emails asynchronously, you are able to rate limit the messenger transport:

framework:
    messenger:
        transports:
            mailer:
                dsn: 'doctrine://default?queue_name=mailer'
                rate_limiter: mailer
        routing:
            'Symfony\Component\Mailer\Messenger\SendEmailMessage': mailer
    rate_limiter:
        mailer:
            policy: fixed_window
            limit: 500
            interval: 60 minutes

However, this will only rate limit the email queue globally - and not per SMTP server. So if you have to use multiple SMTP servers, where some use different rate limits and others do not need to be rate limited at all, this is not ideal.

Thus this PR introduces support for rate limited mailer transports. The changes are fairly straight forward:

  • For each mailer transport you can now also optionally define a rate_limiter, just as with messenger transports.
  • This rate limiter will then be set by the Transport factory, if applicable.
  • The actual rate limiting is done in the AbstractTransport::send() method - using ensureAccepted(), so that a RateLimitExceededException will be thrown.
  • This means that - if you do not use a messenger queue for sending emails, your application is responsible for handling this exception, when you defined a rate limiter on a mailer transport.
  • If you do use a messenger queue then the email message will be put back on the queue, with available_at set to the respective time in the future according to the rate limit.
framework:
    mailer:
        transports:
            hetzner: 
                dsn: smtp://foo:bar@mail.your-server.de:587
                rate_limiter: hetzner
            webgo:
                dsn: smtp://lorem:ipsum@v123.goserver.host:587
                rate_limiter: webgo
            not_rate_limited: smtp://dolor:sit@example.com:587

    rate_limiter:
        # In actuality you will want to set a lower rate limit, depending on whether
        # other applications will also send via the same credentials.
        hetzner:
            policy: fixed_window
            limit: 500
            interval: 60 minutes
        webgo:
            policy: fixed_window
            limit: 50
            interval: 60 minutes

    messenger:
        transports:
            mailer: 
                dsn: 'doctrine://default?queue_name=mailer'
                failure_transport: mailer_failed
            mailer_failed: 'doctrine://default?queue_name=mailer_failed'
        routing:
            'Symfony\Component\Mailer\Messenger\SendEmailMessage': mailer

Tests are still missing, as I wanted to hear comments first :)

@carsonbot carsonbot added this to the 7.3 milestone Mar 16, 2025
@fritzmg fritzmg changed the title Add support for rate limited mailer transports [Mailer][FrameworkBundle] Add support for rate limited mailer transports Mar 16, 2025
@fritzmg fritzmg changed the title [Mailer][FrameworkBundle] Add support for rate limited mailer transports [RFC][Mailer][FrameworkBundle] Add support for rate limited mailer transports Mar 18, 2025
Copy link
Contributor

@Spomky Spomky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi,

Many thanks for the proposal. THis is a nice and useful idea.
I reviewed this PR and it is a good start except the missing tests and a few things I spotted.

@fabpot fabpot modified the milestones: 7.3, 7.4 May 26, 2025
@fritzmg fritzmg closed this Aug 10, 2025
@fritzmg fritzmg force-pushed the feature/mailer-transport-rate-limiter branch from ff86149 to 6d2d7fa Compare August 10, 2025 11:09
@fritzmg fritzmg reopened this Aug 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants