amazon_ses-2.0.x-dev/src/AmazonSesHandler.php

src/AmazonSesHandler.php
<?php

namespace Drupal\amazon_ses;

use Aws\Exception\CredentialsException;
use Aws\Result;
use Aws\SesV2\Exception\SesV2Exception;
use Drupal\amazon_ses\Event\MailSentEvent;
use Drupal\aws\AwsClientFactoryInterface;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelInterface;
use Drupal\Core\Messenger\MessengerInterface;
use Drupal\Core\StringTranslation\StringTranslationTrait;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Mime\Email;

/**
 * Amazon SES service.
 */
class AmazonSesHandler implements AmazonSesHandlerInterface {
  use StringTranslationTrait;

  /**
   * The AWS SesClient.
   *
   * @var \Aws\SesV2\SesV2Client
   */
  protected $client;

  /**
   * The account quota.
   *
   * @var array
   */
  protected $quota = [];

  /**
   * The number of attempts to refresh expired credentials.
   *
   * @var int
   */
  protected $retry = 2;

  public function __construct(
    protected AwsClientFactoryInterface $awsClientFactory,
    protected LoggerChannelInterface $logger,
    protected MessengerInterface $messenger,
    protected EventDispatcherInterface $eventDispatcher,
    protected ConfigFactoryInterface $configFactory,
  ) {
    $this->client = $awsClientFactory->getClient('sesv2');
  }

  /**
   * {@inheritdoc}
   */
  public function getClient() {
    return $this->client;
  }

  /**
   * {@inheritdoc}
   */
  public function verifyClient() {
    return (bool) $this->client;
  }

  /**
   * {@inheritdoc}
   */
  public function send(Email $email) {
    // Avoid an infinite loop on expired (temporary) credentials.
    if ($this->retry <= 0) {
      return FALSE;
    }

    try {
      $result = $this->client->sendEmail([
        'Content' => [
          'Raw' => [
            'Data' => $email->toString(),
          ],
        ],
      ]);

      $event = new MailSentEvent($result['MessageId'], $email);
      $this->eventDispatcher->dispatch($event, MailSentEvent::SENT);

      $throttle = $this->configFactory
        ->get('amazon_ses.settings')
        ->get('throttle');

      if ($throttle) {
        $sleep_time = $this->getSleepTime();
        usleep($sleep_time);
      }

      return $result['MessageId'];
    }
    catch (CredentialsException $e) {
      $this->logger->error($e->getMessage());
      return FALSE;
    }
    catch (SesV2Exception $e) {
      // If the credential has expired, request a new one and try again.
      if ($e->getAwsErrorCode() == 'ExpiredTokenException') {
        $this->retry--;
        $this->refreshClient();
        return $this->send($email);
      }
      $this->logger->error($e->getAwsErrorMessage());
      return FALSE;
    }
  }

  /**
   * Get the number of microseconds to pause for throttling.
   *
   * @return int
   *   The time to sleep in microseconds.
   */
  protected function getSleepTime() {
    $results = $this->getSendQuota();

    // Avoid a division by zero if the quota call failed.
    if (empty($results)) {
      return 0;
    }

    $multiplier = $this->configFactory
      ->get('amazon_ses.settings')
      ->get('multiplier');
    $per_second = ceil((1000000 * $multiplier) / $results['MaxSendRate']);

    return intval($per_second);
  }

  /**
   * {@inheritdoc}
   */
  public function getIdentities() {
    $identities = [];

    try {
      $results = $this->client->listEmailIdentities();

      foreach ($results['EmailIdentities'] as $emailIdentity) {
        $identity = $emailIdentity['IdentityName'];
        $result = $this->client->getEmailIdentity([
          'EmailIdentity' => $identity,
        ]);

        $domain = $result['IdentityType'] == 'DOMAIN';
        $item = [
          'identity' => $identity,
          'status' => $result['VerifiedForSendingStatus'] ? 'Success' : 'Not verified',
          'type' => $domain ? 'Domain' : 'Email Address',
        ];

        if ($domain) {
          $item['dkim'] = $result['DkimAttributes']['SigningEnabled'] ? 'Enabled' : 'Disabled';
        }
        else {
          $item['dkim'] = '';
        }

        $identities[] = $item;
      }
    }
    catch (SesV2Exception $e) {
      $this->logger->error($e->getMessage());
      $this->messenger->addError($this->t('Unable to list identities.'));
    }

    return $identities;
  }

  /**
   * {@inheritdoc}
   */
  public function verifyIdentity($identity) {
    $this->client->createEmailIdentity([
      'EmailIdentity' => $identity,
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function deleteIdentity($identity) {
    $this->client->deleteEmailIdentity([
      'EmailIdentity' => $identity,
    ]);
  }

  /**
   * {@inheritdoc}
   */
  public function getSendQuota() {
    if (empty($this->quota)) {
      try {
        $result = $this->client->getAccount();
        $this->quota = array_map('number_format', $result['SendQuota']);
      }
      catch (SesV2Exception $e) {
        $this->logger->error($e->getMessage());
        $this->messenger->addError($this->t('Unable to retrieve quota.'));
      }
    }
    return $this->quota;
  }

  /**
   * Return the result data as an array.
   *
   * @param \Aws\Result $result
   *   The result from the API call.
   *
   * @return array
   *   The result data.
   */
  protected function resultToArray(Result $result) {
    $array = $result->toArray();
    unset($array['@metadata']);

    return $array;
  }

  /**
   * Get a new SesClient.
   *
   * This helps us if a mail run takes over an hour, in which case the
   * authentication token expires. This should generate us a new one
   * so we can continue.
   */
  protected function refreshClient() {
    $this->client = $this->awsClientFactory->getClient('sesv2');
    $this->logger->info('Refreshing the SesV2 client after the session token expired');
  }

}

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc