Unverified Commit e298fb7b authored by Alex Pott's avatar Alex Pott
Browse files

Issue #3379794 by znerol, alexpott, adamps, berdir, larowlan, andypost,...

Issue #3379794 by znerol, alexpott, adamps, berdir, larowlan, andypost, longwave, dpi, catch: Add symfony mailer transports to Dependency Injection Container (mail delivery layer)
parent 148d8ddb
Loading
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Mailer\Transport;

use Drupal\Core\Site\Settings;
use Symfony\Component\DependencyInjection\Attribute\AutowireDecorated;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportFactoryInterface;
use Symfony\Component\Mailer\Transport\TransportInterface;

/**
 * Command validation decorator for sendmail transport factory.
 */
class SendmailCommandValidationTransportFactory implements TransportFactoryInterface {

  /**
   * Construct command validation decorator for sendmail transport factory.
   *
   * @param \Symfony\Component\Mailer\Transport\TransportFactoryInterface $inner
   *   The decorated sendmail transport factory.
   */
  public function __construct(
    #[AutowireDecorated]
    protected TransportFactoryInterface $inner,
  ) {
  }

  /**
   * {@inheritdoc}
   */
  public function create(Dsn $dsn): TransportInterface {
    $command = $dsn->getOption('command');
    if (!empty($command)) {
      $commands = Settings::get('mailer_sendmail_commands', []);
      if (!in_array($command, $commands, TRUE)) {
        throw new \RuntimeException("Unsafe sendmail command {$command}");
      }
    }

    return $this->inner->create($dsn);
  }

  /**
   * {@inheritdoc}
   */
  public function supports(Dsn $dsn): bool {
    return $this->inner->supports($dsn);
  }

}
+44 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Mailer;

use Drupal\Core\Config\ConfigFactoryInterface;
use Symfony\Component\DependencyInjection\Attribute\AutowireIterator;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;

/**
 * The default mailer transport service factory.
 */
class TransportServiceFactory implements TransportServiceFactoryInterface {

  use TransportServiceFactoryTrait;

  /**
   * Constructs a new transport service factory.
   *
   * @param Iterable<TransportFactoryInterface> $factories
   *   A list of transport factories.
   * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
   *   The config factory service.
   */
  public function __construct(
    #[AutowireIterator(tag: 'mailer.transport_factory')]
    iterable $factories,
    protected ConfigFactoryInterface $configFactory,
  ) {
    $this->factories = $factories;
  }

  /**
   * {@inheritdoc}
   */
  public function createTransport(): TransportInterface {
    $dsn = $this->configFactory->get('system.mail')->get('mailer_dsn');
    $dsnObject = new Dsn(...$dsn);
    return $this->fromDsnObject($dsnObject);
  }

}
+28 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Mailer;

use Symfony\Component\Mailer\Transport\TransportInterface;

/**
 * An interface defining mailer transport service factory implementations.
 *
 * The transport service factory is responsible to create a transport instance
 * according to the site configuration. The default service factory looks up the
 * `mailer_dsn` key from the `system.mail` config and returns an appropriate
 * transport implementation.
 *
 * Contrib and custom code may choose to replace or decorate the transport
 * service factory in order to provide a mailer transport instance which
 * requires more complex setup.
 */
interface TransportServiceFactoryInterface {

  /**
   * Creates and returns a configured mailer transport class.
   */
  public function createTransport(): TransportInterface;

}
+42 −0
Original line number Diff line number Diff line
<?php

declare(strict_types=1);

namespace Drupal\Core\Mailer;

use Symfony\Component\Mailer\Exception\UnsupportedSchemeException;
use Symfony\Component\Mailer\Transport\Dsn;
use Symfony\Component\Mailer\Transport\TransportInterface;

/**
 * A trait containing helper methods for transport service construction.
 */
trait TransportServiceFactoryTrait {

  /**
   * A list of transport factories.
   *
   * @var Iterable<TransportFactoryInterface>
   */
  protected iterable $factories;

  /**
   * Constructs a transport instance given a DSN object.
   *
   * @param \Symfony\Component\Mailer\Transport\Dsn $dsn
   *   The mailer DSN object.
   *
   * @throws \Symfony\Component\Mailer\Exception\IncompleteDsnException
   * @throws \Symfony\Component\Mailer\Exception\UnsupportedSchemeException
   */
  protected function fromDsnObject(Dsn $dsn): TransportInterface {
    foreach ($this->factories as $factory) {
      if ($factory->supports($dsn)) {
        return $factory->create($dsn);
      }
    }

    throw new UnsupportedSchemeException($dsn);
  }

}
+6 −0
Original line number Diff line number Diff line
name: Mailer
type: module
description: 'Provides an experimental API to build and deliver email messages.'
package: Core (Experimental)
lifecycle: experimental
version: VERSION
Loading