mailers.php 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321
  1. <?php
  2. /**
  3. * Wrapper mailer for old addons registering the "mail" method (ultra deprecated).
  4. */
  5. class NewsletterMailMethodWrapper extends NewsletterMailer {
  6. var $mail_method;
  7. /**
  8. * The reference to the mail method.
  9. *
  10. * @param callback $callable Must be an array with object and method to call, no other callback formats allowed.
  11. */
  12. function __construct($callable) {
  13. parent::__construct(strtolower(get_class($callable[0])), array());
  14. $this->mail_method = $callable;
  15. }
  16. function get_description() {
  17. if ($this->mail_method != null) {
  18. return 'Mail method of ' . get_class($this->mail_method[0]);
  19. } else {
  20. return 'Undetectable mailer class';
  21. }
  22. }
  23. function send($message) {
  24. if ($this->mail_method != null) {
  25. $r = call_user_func($this->mail_method, $message->to, $message->subject, array('html' => $message->body, 'text' => $message->body_text), $message->headers);
  26. if (!$r) {
  27. $message->error = 'Unreported error';
  28. return new WP_Error(self::ERROR_GENERIC, 'Unreported error');
  29. }
  30. } else {
  31. $message->error = 'Mail mathod not available';
  32. return new WP_Error(self::ERROR_FATAL, 'Mail method not available');
  33. }
  34. return true;
  35. }
  36. }
  37. /**
  38. * Wrapper Mailer for old addons registering the "mail" method (deprecated).
  39. */
  40. class NewsletterOldMailerWrapper extends NewsletterMailer {
  41. var $mailer;
  42. /**
  43. * Old mailer plugin (actually untyped object)
  44. * @param object $mailer
  45. */
  46. function __construct($mailer) {
  47. $this->mailer = $mailer;
  48. // We have not a name, build it from the class name... and of course, no options.
  49. parent::__construct(strtolower(get_class($mailer)), array());
  50. $this->description = 'Mailer wrapper for ' . get_class($mailer);
  51. }
  52. /**
  53. * Only send() needs to be implemented all other method will use the defail base-class implementation
  54. *
  55. * @param TNP_Mailer_Message $message
  56. * @return \WP_Error|boolean
  57. */
  58. function send($message) {
  59. // The old mailer manages itself the from field
  60. $r = $this->mailer->mail($message->to, $message->subject, array('html' => $message->body, 'text' => $message->body_text), $message->headers);
  61. if (!$r) {
  62. if (isset($this->mailer->result)) {
  63. $message->error = $this->mailer->result;
  64. return new WP_Error(self::ERROR_GENERIC, $this->mailer->result);
  65. } else {
  66. $message->error = 'Unknown error';
  67. return new WP_Error(self::ERROR_GENERIC, 'Unknown error');
  68. }
  69. }
  70. return true;
  71. }
  72. }
  73. /**
  74. * Standard Mailer which uses the wp_mail() function of WP.
  75. */
  76. class NewsletterDefaultMailer extends NewsletterMailer {
  77. var $filter_active = false;
  78. /**
  79. * Static to be accessed in the hook: on some installation the object $this is not working, we're still trying to understand why
  80. * @var TNP_Mailer_Message
  81. */
  82. var $current_message = null;
  83. function __construct() {
  84. parent::__construct('default', Newsletter::instance()->get_options('smtp'));
  85. }
  86. function get_description() {
  87. // TODO: check if overloaded
  88. return 'wp_mail() WordPress function (could be extended by a SMTP plugin)';
  89. }
  90. function fix_mailer($mailer) {
  91. $newsletter = Newsletter::instance();
  92. if (!empty($newsletter->options['content_transfer_encoding'])) {
  93. $mailer->Encoding = $newsletter->options['content_transfer_encoding'];
  94. } else {
  95. $mailer->Encoding = 'base64';
  96. }
  97. // If there is not a current message, wp_mail() was not called by us
  98. if (is_null($this->current_message)) {
  99. return;
  100. }
  101. /* @var $mailer PHPMailer */
  102. $mailer->Sender = $newsletter->options['return_path'];
  103. if (!empty($this->current_message->current_message->body) && !empty($this->current_message->current_message->body_text)) {
  104. $mailer->AltBody = $this->current_message->current_message->body_text;
  105. }
  106. }
  107. function send($message) {
  108. if (!$this->filter_active) {
  109. add_action('phpmailer_init', array($this, 'fix_mailer'), 100);
  110. $this->filter_active = true;
  111. }
  112. $newsletter = Newsletter::instance();
  113. $wp_mail_headers = array();
  114. // TODO: Manage the from address
  115. $wp_mail_headers[] = 'From: "' . $newsletter->options['sender_name'] . '" <' . $newsletter->options['sender_email'] . '>';
  116. if (!empty($newsletter->options['reply_to'])) {
  117. $wp_mail_headers[] = 'Reply-To: ' . $newsletter->options['reply_to'];
  118. }
  119. // Manage from and from name
  120. if (!empty($message->headers)) {
  121. foreach ($message->headers as $key => $value) {
  122. $wp_mail_headers[] = $key . ': ' . $value;
  123. }
  124. }
  125. if (!empty($message->body)) {
  126. $wp_mail_headers[] = 'Content-Type: text/html;charset=UTF-8';
  127. $body = $message->body;
  128. } else if (!empty($message->body_text)) {
  129. $wp_mail_headers[] = 'Content-Type: text/plain;charset=UTF-8';
  130. $body = $message->body_text;
  131. } else {
  132. $message->error = 'Empty body';
  133. return new WP_Error(self::ERROR_GENERIC, 'Message format');
  134. }
  135. $this->current_message = $message;
  136. $r = wp_mail($message->to, $message->subject, $body, $wp_mail_headers);
  137. $this->current_message = null;
  138. if (!$r) {
  139. $last_error = error_get_last();
  140. if (is_array($last_error)) {
  141. $message->error = $last_error['message'];
  142. if (stripos($message->error, 'Could not instantiate mail function') || stripos($message->error, 'Failed to connect to mailserver')) {
  143. return new WP_Error(self::ERROR_FATAL, $last_error['message']);
  144. } else {
  145. return new WP_Error(self::ERROR_GENERIC, $last_error['message']);
  146. }
  147. } else {
  148. $message->error = 'No error explanation reported';
  149. return new WP_Error(self::ERROR_GENERIC, 'No error message reported');
  150. }
  151. }
  152. return true;
  153. }
  154. }
  155. /**
  156. * Standard Mailer which uses the wp_mail() function of WP.
  157. */
  158. class NewsletterDefaultSMTPMailer extends NewsletterMailer {
  159. var $mailer = null;
  160. function __construct($options) {
  161. parent::__construct('internal-smtp', $options);
  162. }
  163. function get_description() {
  164. return 'Internal SMTP (deprecated)';
  165. }
  166. /**
  167. *
  168. * @param TNP_Mailer_Message $message
  169. * @return \WP_Error|boolean
  170. */
  171. public function send($message) {
  172. $logger = $this->get_logger();
  173. $logger->debug('Start sending to ' . $message->to);
  174. $mailer = $this->get_mailer();
  175. if (!empty($message->body)) {
  176. $mailer->IsHTML(true);
  177. $mailer->Body = $message->body;
  178. $mailer->AltBody = $message->body_text;
  179. } else {
  180. $mailer->IsHTML(false);
  181. $mailer->Body = $message->body_text;
  182. $mailer->AltBody = '';
  183. }
  184. $mailer->Subject = $message->subject;
  185. $mailer->ClearCustomHeaders();
  186. if (!empty($message->headers)) {
  187. foreach ($message->headers as $key => $value) {
  188. $mailer->AddCustomHeader($key . ': ' . $value);
  189. }
  190. }
  191. if ($message->from) {
  192. $logger->debug('Alternative from available');
  193. $mailer->setFrom($message->from, $message->from_name);
  194. } else {
  195. $newsletter = Newsletter::instance();
  196. $mailer->setFrom($newsletter->options['sender_email'], $newsletter->options['sender_name']);
  197. }
  198. $mailer->ClearAddresses();
  199. $mailer->AddAddress($message->to);
  200. $mailer->Send();
  201. if ($mailer->IsError()) {
  202. $logger->error($mailer->ErrorInfo);
  203. // If the error is due to SMTP connection, the mailer cannot be reused since it does not clean up the connection
  204. // on error.
  205. //$this->mailer = null;
  206. $message->error = $mailer->ErrorInfo;
  207. return new WP_Error(self::ERROR_GENERIC, $mailer->ErrorInfo);
  208. }
  209. $logger->debug('Sent ' . $message->to);
  210. //$logger->error('Time: ' . (microtime(true) - $start) . ' seconds');
  211. return true;
  212. }
  213. /**
  214. *
  215. * @return PHPMailer
  216. */
  217. function get_mailer() {
  218. if ($this->mailer) {
  219. return $this->mailer;
  220. }
  221. $logger = $this->get_logger();
  222. $logger->debug('Setting up PHP mailer');
  223. require_once ABSPATH . WPINC . '/class-phpmailer.php';
  224. require_once ABSPATH . WPINC . '/class-smtp.php';
  225. $this->mailer = new PHPMailer();
  226. $this->mailer->IsSMTP();
  227. $this->mailer->Host = $this->options['host'];
  228. if (!empty($this->options['port'])) {
  229. $this->mailer->Port = (int) $this->options['port'];
  230. }
  231. if (!empty($this->options['user'])) {
  232. $this->mailer->SMTPAuth = true;
  233. $this->mailer->Username = $this->options['user'];
  234. $this->mailer->Password = $this->options['pass'];
  235. }
  236. $this->mailer->SMTPKeepAlive = true;
  237. $this->mailer->SMTPSecure = $this->options['secure'];
  238. $this->mailer->SMTPAutoTLS = false;
  239. if ($this->options['ssl_insecure'] == 1) {
  240. $this->mailer->SMTPOptions = array(
  241. 'ssl' => array(
  242. 'verify_peer' => false,
  243. 'verify_peer_name' => false,
  244. 'allow_self_signed' => true
  245. )
  246. );
  247. }
  248. $newsletter = Newsletter::instance();
  249. // if (!empty($newsletter->options['content_transfer_encoding'])) {
  250. // $this->mailer->Encoding = $newsletter->options['content_transfer_encoding'];
  251. // } else {
  252. // $this->mailer->Encoding = 'base64';
  253. // }
  254. $this->mailer->CharSet = 'UTF-8';
  255. $this->mailer->From = $newsletter->options['sender_email'];
  256. if (!empty($newsletter->options['return_path'])) {
  257. $this->mailer->Sender = $newsletter->options['return_path'];
  258. }
  259. if (!empty($newsletter->options['reply_to'])) {
  260. $this->mailer->AddReplyTo($newsletter->options['reply_to']);
  261. }
  262. $this->mailer->FromName = $newsletter->options['sender_name'];
  263. return $this->mailer;
  264. }
  265. }