Sin descripción

Mailer.php 7.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. <?php
  2. namespace MailPoet\Mailer;
  3. if (!defined('ABSPATH')) exit;
  4. use MailPoet\DI\ContainerWrapper;
  5. use MailPoet\Mailer\Methods\AmazonSES;
  6. use MailPoet\Mailer\Methods\ErrorMappers\AmazonSESMapper;
  7. use MailPoet\Mailer\Methods\ErrorMappers\MailPoetMapper;
  8. use MailPoet\Mailer\Methods\ErrorMappers\PHPMailMapper;
  9. use MailPoet\Mailer\Methods\ErrorMappers\SendGridMapper;
  10. use MailPoet\Mailer\Methods\ErrorMappers\SMTPMapper;
  11. use MailPoet\Mailer\Methods\MailPoet;
  12. use MailPoet\Mailer\Methods\PHPMail;
  13. use MailPoet\Mailer\Methods\SendGrid;
  14. use MailPoet\Mailer\Methods\SMTP;
  15. use MailPoet\Services\AuthorizedEmailsController;
  16. use MailPoet\Settings\SettingsController;
  17. use MailPoet\WP\Functions as WPFunctions;
  18. class Mailer {
  19. public $mailerConfig;
  20. public $sender;
  21. public $replyTo;
  22. public $returnPath;
  23. public $mailerInstance;
  24. /** @var SettingsController */
  25. private $settings;
  26. /** @var WPFunctions */
  27. private $wp;
  28. const MAILER_CONFIG_SETTING_NAME = 'mta';
  29. const SENDING_LIMIT_INTERVAL_MULTIPLIER = 60;
  30. const METHOD_MAILPOET = 'MailPoet';
  31. const METHOD_AMAZONSES = 'AmazonSES';
  32. const METHOD_SENDGRID = 'SendGrid';
  33. const METHOD_PHPMAIL = 'PHPMail';
  34. const METHOD_SMTP = 'SMTP';
  35. public function __construct(
  36. SettingsController $settings = null,
  37. WPFunctions $wp = null
  38. ) {
  39. if (!$settings) {
  40. $settings = SettingsController::getInstance();
  41. }
  42. if (!$wp) {
  43. $wp = WPFunctions::get();
  44. }
  45. $this->settings = $settings;
  46. $this->wp = $wp;
  47. }
  48. public function init($mailer = false, $sender = false, $replyTo = false, $returnPath = false) {
  49. $this->mailerConfig = $this->getMailerConfig($mailer);
  50. $this->sender = $this->getSenderNameAndAddress($sender);
  51. $this->replyTo = $this->getReplyToNameAndAddress($replyTo);
  52. $this->returnPath = $this->getReturnPathAddress($returnPath);
  53. $this->mailerInstance = $this->buildMailer();
  54. }
  55. public function send($newsletter, $subscriber, $extraParams = []) {
  56. if (!$this->mailerInstance) {
  57. $this->init();
  58. }
  59. $subscriber = $this->formatSubscriberNameAndEmailAddress($subscriber);
  60. return $this->mailerInstance->send($newsletter, $subscriber, $extraParams);
  61. }
  62. private function buildMailer() {
  63. switch ($this->mailerConfig['method']) {
  64. case self::METHOD_AMAZONSES:
  65. $mailerInstance = new AmazonSES(
  66. $this->mailerConfig['region'],
  67. $this->mailerConfig['access_key'],
  68. $this->mailerConfig['secret_key'],
  69. $this->sender,
  70. $this->replyTo,
  71. $this->returnPath,
  72. new AmazonSESMapper()
  73. );
  74. break;
  75. case self::METHOD_MAILPOET:
  76. $mailerInstance = new MailPoet(
  77. $this->mailerConfig['mailpoet_api_key'],
  78. $this->sender,
  79. $this->replyTo,
  80. new MailPoetMapper(),
  81. ContainerWrapper::getInstance()->get(AuthorizedEmailsController::class)
  82. );
  83. break;
  84. case self::METHOD_SENDGRID:
  85. $mailerInstance = new SendGrid(
  86. $this->mailerConfig['api_key'],
  87. $this->sender,
  88. $this->replyTo,
  89. new SendGridMapper()
  90. );
  91. break;
  92. case self::METHOD_PHPMAIL:
  93. $mailerInstance = new PHPMail(
  94. $this->sender,
  95. $this->replyTo,
  96. $this->returnPath,
  97. new PHPMailMapper()
  98. );
  99. break;
  100. case self::METHOD_SMTP:
  101. $mailerInstance = new SMTP(
  102. $this->mailerConfig['host'],
  103. $this->mailerConfig['port'],
  104. $this->mailerConfig['authentication'],
  105. $this->mailerConfig['encryption'],
  106. $this->sender,
  107. $this->replyTo,
  108. $this->returnPath,
  109. new SMTPMapper(),
  110. $this->mailerConfig['login'],
  111. $this->mailerConfig['password']
  112. );
  113. break;
  114. default:
  115. throw new \Exception(__('Mailing method does not exist.', 'mailpoet'));
  116. }
  117. return $mailerInstance;
  118. }
  119. private function getMailerConfig($mailer = false) {
  120. if (!$mailer) {
  121. $mailer = $this->settings->get(self::MAILER_CONFIG_SETTING_NAME);
  122. if (!$mailer || !isset($mailer['method'])) throw new \Exception(__('Mailer is not configured.', 'mailpoet'));
  123. }
  124. return $mailer;
  125. }
  126. private function getSenderNameAndAddress($sender = false) {
  127. if (empty($sender)) {
  128. $sender = $this->settings->get('sender', []);
  129. if (empty($sender['address'])) throw new \Exception(__('Sender name and email are not configured.', 'mailpoet'));
  130. }
  131. $fromName = $this->encodeAddressNamePart($sender['name']);
  132. return [
  133. 'from_name' => $fromName,
  134. 'from_email' => $sender['address'],
  135. 'from_name_email' => sprintf('%s <%s>', $fromName, $sender['address']),
  136. ];
  137. }
  138. public function getReplyToNameAndAddress($replyTo = []) {
  139. if (!$replyTo) {
  140. $replyTo = $this->settings->get('reply_to');
  141. $replyTo['name'] = (!empty($replyTo['name'])) ?
  142. $replyTo['name'] :
  143. $this->sender['from_name'];
  144. $replyTo['address'] = (!empty($replyTo['address'])) ?
  145. $replyTo['address'] :
  146. $this->sender['from_email'];
  147. }
  148. if (empty($replyTo['address'])) {
  149. $replyTo['address'] = $this->sender['from_email'];
  150. }
  151. $replyToName = $this->encodeAddressNamePart($replyTo['name']);
  152. return [
  153. 'reply_to_name' => $replyToName,
  154. 'reply_to_email' => $replyTo['address'],
  155. 'reply_to_name_email' => sprintf('%s <%s>', $replyToName, $replyTo['address']),
  156. ];
  157. }
  158. public function getReturnPathAddress($returnPath) {
  159. if ($returnPath) {
  160. return $returnPath;
  161. }
  162. $bounceAddress = $this->settings->get('bounce.address');
  163. return $this->wp->isEmail($bounceAddress) ? $bounceAddress : null;
  164. }
  165. /**
  166. * @param \MailPoet\Models\Subscriber|array|string $subscriber
  167. */
  168. public function formatSubscriberNameAndEmailAddress($subscriber) {
  169. $subscriber = (is_object($subscriber)) ? $subscriber->asArray() : $subscriber;
  170. if (!is_array($subscriber)) return $subscriber;
  171. if (isset($subscriber['address'])) $subscriber['email'] = $subscriber['address'];
  172. $firstName = (isset($subscriber['first_name'])) ? $subscriber['first_name'] : '';
  173. $lastName = (isset($subscriber['last_name'])) ? $subscriber['last_name'] : '';
  174. $fullName = (isset($subscriber['full_name'])) ? $subscriber['full_name'] : null;
  175. if (!$firstName && !$lastName && !$fullName) return $subscriber['email'];
  176. $fullName = is_null($fullName) ? sprintf('%s %s', $firstName, $lastName) : $fullName;
  177. $fullName = trim(preg_replace('!\s\s+!', ' ', $fullName));
  178. $fullName = $this->encodeAddressNamePart($fullName);
  179. $subscriber = sprintf(
  180. '%s <%s>',
  181. $fullName,
  182. $subscriber['email']
  183. );
  184. return $subscriber;
  185. }
  186. public function encodeAddressNamePart($name) {
  187. if (mb_detect_encoding($name) === 'ASCII') return $name;
  188. // encode non-ASCII string as per RFC 2047 (https://www.ietf.org/rfc/rfc2047.txt)
  189. return sprintf('=?utf-8?B?%s?=', base64_encode($name));
  190. }
  191. public static function formatMailerErrorResult(MailerError $error) {
  192. return [
  193. 'response' => false,
  194. 'error' => $error,
  195. ];
  196. }
  197. public static function formatMailerSendSuccessResult() {
  198. return [
  199. 'response' => true,
  200. ];
  201. }
  202. }