Skip to content

ISSUE-345: mail sending #340

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 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 39 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ phpList is an open source newsletter manager. This project is a rewrite of the

## About this package

This is the core module of the successor to phpList 3. It will have the
This is the core module of the successor to phpList 3. It will have the
following responsibilities:

* provide access to the DB via Doctrine models and repositories (and raw SQL
Expand All @@ -41,7 +41,7 @@ Since this package is only a service required to run a full installation of **ph

## Contributing to this package

Contributions to phpList repositories are highly welcomed! To get started please take a look at the [contribution guide](.github/CONTRIBUTING.md). It contains everything you would need to make your first contribution including how to run local style checks and run tests.
Contributions to phpList repositories are highly welcomed! To get started please take a look at the [contribution guide](.github/CONTRIBUTING.md). It contains everything you would need to make your first contribution including how to run local style checks and run tests.

### Code of Conduct

Expand All @@ -53,9 +53,11 @@ this code.
## Structure

* [Class Docs][docs/phpdoc/]
* [Mailer Transports](docs/mailer-transports.md) - How to use different email providers (Gmail, Amazon SES, Mailchimp, SendGrid)
* [Class structure overview](docs/ClassStructure.md)
* [Graphic domain model](docs/DomainModel/DomainModel.svg) and
a [description of the domain entities](docs/DomainModel/Entities.md)
* [Mailer Transports](docs/mailer-transports.md) - How to use different email providers (Gmail, Amazon SES, Mailchimp, SendGrid)


## Running the web server
Expand All @@ -79,9 +81,9 @@ already in use, on the next free port after 8000).

You can stop the server with CTRL + C.

#### Development and Documentation
#### Development and Documentation

We use `phpDocumentor` to automatically generate documentation for classes. To make this process efficient and easier, you are required to properly "document" your `classes`,`properties`, `methods` ... by annotating them with [docblocks](https://docs.phpdoc.org/latest/guide/guides/docblocks.html).
We use `phpDocumentor` to automatically generate documentation for classes. To make this process efficient and easier, you are required to properly "document" your `classes`,`properties`, `methods` ... by annotating them with [docblocks](https://docs.phpdoc.org/latest/guide/guides/docblocks.html).

More about generatings docs in [PHPDOC.md](PHPDOC.md)

Expand Down Expand Up @@ -124,12 +126,12 @@ listed in the `extra` section of the module's `composer.json` like this:

```json
"extra": {
"phplist/core": {
"bundles": [
"Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle",
"PhpList\\Core\\EmptyStartPageBundle\\PhpListEmptyStartPageBundle"
]
}
"phplist/core": {
"bundles": [
"Symfony\\Bundle\\FrameworkBundle\\FrameworkBundle",
"PhpList\\Core\\EmptyStartPageBundle\\PhpListEmptyStartPageBundle"
]
}
}
```

Expand All @@ -144,32 +146,32 @@ the `extra` section of the module's `composer.json` like this:

```json
"extra": {
"phplist/core": {
"routes": {
"homepage": {
"resource": "@PhpListEmptyStartPageBundle/Controller/",
"type": "annotation"
}
}
"phplist/core": {
"routes": {
"homepage": {
"resource": "@PhpListEmptyStartPageBundle/Controller/",
"type": "annotation"
}
}
}
}
```

You can also provide system configuration for your module:

```json
"extra": {
"phplist/core": {
"configuration": {
"framework": {
"templating": {
"engines": [
"twig"
]
}
}
"phplist/core": {
"configuration": {
"framework": {
"templating": {
"engines": [
"twig"
]
}
}
}
}
}
```

Expand Down Expand Up @@ -204,6 +206,17 @@ phpList module), please use the
[REST API](https://github.com/phpList/rest-api).


## Email Configuration

phpList supports multiple email transport providers through Symfony Mailer. The following transports are included:

* Gmail
* Amazon SES
* Mailchimp Transactional (Mandrill)
* SendGrid

For detailed configuration instructions, see the [Mailer Transports documentation](docs/mailer-transports.md).

## Copyright

phpList is copyright (C) 2000-2021 [phpList Ltd](https://www.phplist.com/).
9 changes: 8 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,14 @@
"masterminds/html5": "^2.9",
"ext-dom": "*",
"league/csv": "^9.23.0",
"doctrine/doctrine-migrations-bundle": "^3.4"
"doctrine/doctrine-migrations-bundle": "^3.4",
"symfony/mailer": "^6.4",
"symfony/google-mailer": "^6.4",
"symfony/amazon-mailer": "^6.4",
"symfony/mailchimp-mailer": "^6.4",
"symfony/sendgrid-mailer": "^6.4",
"symfony/twig-bundle": "^6.4",
"symfony/messenger": "^6.4"
},
"require-dev": {
"phpunit/phpunit": "^9.5",
Expand Down
2 changes: 1 addition & 1 deletion config/PHPMD/rules.xml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
<!-- rules from the "naming" rule set -->
<rule ref="rulesets/naming.xml/ShortVariable">
<properties>
<property name="exceptions" value="id,ip"/>
<property name="exceptions" value="id,ip,cc"/>
</properties>
</rule>
<rule ref="rulesets/naming.xml/LongVariable">
Expand Down
2 changes: 2 additions & 0 deletions config/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,3 +40,5 @@ framework:
serializer:
enabled: true
enable_attributes: true
mailer:
dsn: '%app.mailer_dsn%'
26 changes: 26 additions & 0 deletions config/packages/messenger.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# This file is the Symfony Messenger configuration for asynchronous processing
framework:
messenger:
# Uncomment this (and the failed transport below) to send failed messages to this transport for later handling.
# failure_transport: failed

transports:
# https://symfony.com/doc/current/messenger.html#transport-configuration
async_email:
dsn: '%env(MESSENGER_TRANSPORT_DSN)%'
options:
auto_setup: true
use_notify: true
check_delayed_interval: 60000
retry_strategy:
max_retries: 3
# milliseconds delay
delay: 1000
multiplier: 2
max_delay: 0

# failed: 'doctrine://default?queue_name=failed'

routing:
# Route your messages to the transports
'PhpList\Core\Domain\Messaging\Message\AsyncEmailMessage': async_email
6 changes: 6 additions & 0 deletions config/parameters.yml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ parameters:
database_password: '%%env(PHPLIST_DATABASE_PASSWORD)%%'
env(PHPLIST_DATABASE_PASSWORD): 'phplist'

# mailer configs
app.mailer_from: '%%env(MAILER_FROM)%%'
env(MAILER_FROM): '[email protected]'
app.mailer_dsn: '%%env(MAILER_DSN)%%'
env(MAILER_DSN): 'smtp://username:[email protected]:2525'

# A secret key that's used to generate certain security-related tokens
secret: '%%env(PHPLIST_SECRET)%%'
env(PHPLIST_SECRET): %1$s
5 changes: 5 additions & 0 deletions config/services.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ services:
public: true
tags: [controller.service_arguments]

# Register message handlers for Symfony Messenger
PhpList\Core\Domain\Messaging\MessageHandler\:
resource: '../src/Domain/Messaging/MessageHandler'
tags: ['messenger.message_handler']

doctrine.orm.metadata.annotation_reader:
alias: doctrine.annotation_reader

Expand Down
10 changes: 10 additions & 0 deletions config/services/commands.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
services:
_defaults:
autowire: true
autoconfigure: true
public: false

PhpList\Core\Domain\Messaging\Command\:
resource: '../../src/Domain/Messaging/Command'
tags: ['console.command']

6 changes: 6 additions & 0 deletions config/services/managers.yml
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,9 @@ services:
autowire: true
autoconfigure: true
public: true

PhpList\Core\Domain\Messaging\Service\EmailService:
autowire: true
autoconfigure: true
arguments:
$defaultFromEmail: '%app.mailer_from%'
4 changes: 2 additions & 2 deletions config/packages/app.yml → config/services/parameters.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
app:
config:
parameters:
app.config:
message_from_address: '[email protected]'
admin_address: '[email protected]'
default_message_age: 15768000
Expand Down
102 changes: 102 additions & 0 deletions docs/AsyncEmailSending.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
# Asynchronous Email Sending in phpList

This document explains how to use the asynchronous email sending functionality in phpList.

## Overview

phpList now supports sending emails asynchronously using Symfony Messenger. This means that when you send an email, it is queued for delivery rather than being sent immediately. This has several benefits:

1. **Improved Performance**: Your application doesn't have to wait for the email to be sent before continuing execution
2. **Better Reliability**: If the email server is temporarily unavailable, the message remains in the queue and will be retried automatically
3. **Scalability**: You can process the email queue separately from your main application, allowing for better resource management

## Configuration

The asynchronous email functionality is configured in `config/packages/messenger.yaml` and uses the `MESSENGER_TRANSPORT_DSN` environment variable defined in `config/parameters.yml`.

By default, the system uses Doctrine (database) as the transport for queued messages:

```yaml
env(MESSENGER_TRANSPORT_DSN): 'doctrine://default?auto_setup=true'
```

You can change this to use other transports supported by Symfony Messenger, such as:

- **AMQP (RabbitMQ)**: `amqp://guest:guest@localhost:5672/%2f/messages`
- **Redis**: `redis://localhost:6379/messages`
- **In-Memory (for testing)**: `in-memory://`

## Using Asynchronous Email Sending

### Basic Usage

The `EmailService` class now sends emails asynchronously by default:

```php
// This will queue the email for sending
$emailService->sendEmail($email);
```

### Synchronous Sending

If you need to send an email immediately (synchronously), you can use the `sendEmailSync` method:

```php
// This will send the email immediately
$emailService->sendEmailSync($email);
```

### Bulk Emails

For sending to multiple recipients:

```php
// Asynchronous (queued)
$emailService->sendBulkEmail($recipients, $subject, $text, $html);

// Synchronous (immediate)
$emailService->sendBulkEmailSync($recipients, $subject, $text, $html);
```

## Testing Email Sending

You can test the email functionality using the built-in command:

```bash
# Queue an email for asynchronous sending
bin/console app:send-test-email [email protected]

# Send an email synchronously (immediately)
bin/console app:send-test-email [email protected] --sync
```

## Processing the Email Queue

To process queued emails, you need to run the Symfony Messenger worker:

```bash
bin/console messenger:consume async_email
```

For production environments, it's recommended to run this command as a background service or using a process manager like Supervisor.

## Monitoring

You can monitor the queue status using the following commands:

```bash
# View the number of messages in the queue
bin/console messenger:stats

# View failed messages
bin/console messenger:failed:show
```

## Troubleshooting

If emails are not being sent:

1. Make sure the messenger worker is running
2. Check for failed messages using `bin/console messenger:failed:show`
3. Verify your mailer configuration in `config/parameters.yml`
4. Try sending an email synchronously to test the mailer configuration
2 changes: 1 addition & 1 deletion docs/ClassStructure.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ database access code in these classes.

### Repository/

These classes are reponsible for reading domain models from the database,
These classes are responsible for reading domain models from the database,
for writing them there, and for other database queries.


Expand Down
Loading