|
<?php |
|
|
|
class EP_Email |
|
{ |
|
/** @var string Where to sent to */ |
|
protected $to; |
|
|
|
/** @var string Where to sent to as a hidden copy */ |
|
protected $cc; |
|
|
|
/** @var string Where to sent to as a hidden copy */ |
|
protected $bcc; |
|
|
|
/** @var string Email Charset */ |
|
protected $charset = 'UTF-8'; |
|
|
|
/** @var array Email Headers */ |
|
protected $headers = []; |
|
|
|
/** @var string Subject of the email */ |
|
protected $subject; |
|
|
|
/** @var string */ |
|
protected $from_name; |
|
|
|
/** @var string */ |
|
protected $from_email; |
|
|
|
/** |
|
* @var string |
|
*/ |
|
protected $reply_to; |
|
|
|
/** |
|
* Message of the email |
|
* |
|
* @var string |
|
*/ |
|
protected $message; |
|
|
|
/** |
|
* Attachments that will be passed to the wp_mail |
|
* |
|
* @var array |
|
*/ |
|
protected $attachments = []; |
|
|
|
/** |
|
* Info if the email has been sent. |
|
* |
|
* @var bool |
|
*/ |
|
protected $is_sent = false; |
|
|
|
/** |
|
* Params that will be passed |
|
* to a subject and message of the email |
|
* |
|
* @var array |
|
*/ |
|
protected $placeholders = []; |
|
|
|
/** @var string */ |
|
protected $stored_php_mailer_charset; |
|
|
|
/** |
|
* @var array |
|
*/ |
|
protected $before_send_listeners = []; |
|
|
|
/** |
|
* @var array |
|
*/ |
|
protected $after_sent_listeners = []; |
|
|
|
/** @var array */ |
|
protected $failed_listeners = []; |
|
|
|
|
|
/** |
|
* EP_Email constructor. |
|
* |
|
* @param string $to Comma Separated Email where to sent to |
|
* @param string $subject Subject of the email |
|
* @param string $message An Email message |
|
* @param array $headers Optional. Headers for email. |
|
* @param array $attachments Optional. Files to attach. |
|
* @param array $placeholders Optional. Key value pair that will be performed in the subject and Message. |
|
* |
|
* @throws Exception |
|
*/ |
|
public function __construct($to, $subject, $message, array $headers = [], array $attachments = [], array $placeholders = []) |
|
{ |
|
$this->setTo($to); |
|
$this->setSubject($subject); |
|
$this->setMessage($message); |
|
$this->setHeaders($headers); |
|
$this->setAttachments($attachments); |
|
$this->setPlaceholders($placeholders); |
|
} |
|
|
|
/** |
|
* Factory. |
|
* |
|
* @param string $to Email where to sent to |
|
* @param string $subject Subject of the email |
|
* @param string $message An Email message |
|
* @param array $headers Optional. Headers for the email. |
|
* @param array $attachments Optional. Files to attach. |
|
* @param array $placeholders Optional. Key value pair that will be performed in the subject and Message. |
|
* |
|
* @return EP_Email |
|
* @throws Exception |
|
* |
|
*/ |
|
public static function make($to, $subject, $message, array $headers = [], array $attachments = [], array $placeholders = []) |
|
{ |
|
return new static($to, $subject, $message, $headers, $attachments, $placeholders); |
|
} |
|
|
|
/** |
|
* @param array $attachments Optional. Files to attach. |
|
* |
|
* @return $this |
|
*/ |
|
public function setAttachments(array $attachments) |
|
{ |
|
$this->attachments = $attachments; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @param string $to Comma separated list of emails |
|
* @return $this |
|
* @throws RuntimeException |
|
*/ |
|
public function setTo($to) |
|
{ |
|
$to = $this->sanitizeEmail($to); |
|
|
|
if (!$to) { |
|
throw new RuntimeException('`$to` should contain an email address'); |
|
} |
|
|
|
$this->to = apply_filters('ep.email_to', $to, $this); |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @param string $cc Comma separated list of emails |
|
* @return $this |
|
* @throws RuntimeException |
|
*/ |
|
public function setCc($cc) |
|
{ |
|
$cc = $this->sanitizeEmail($cc); |
|
|
|
if (!$cc) { |
|
throw new RuntimeException('`$cc` should contain an email address'); |
|
} |
|
|
|
$this->cc = apply_filters('ep.email_cc', $cc, $this); |
|
|
|
return $this->addHeaders('cc: ' . $cc); |
|
} |
|
|
|
/** |
|
* @param string $bcc Comma separated list of emails |
|
* @return $this |
|
* @throws RuntimeException |
|
*/ |
|
public function setBcc($bcc) |
|
{ |
|
$bcc = $this->sanitizeEmail($bcc); |
|
|
|
if (!$bcc) { |
|
throw new RuntimeException('`$bcc` should contain an email address'); |
|
} |
|
|
|
$this->bcc = apply_filters('ep.email_bcc', $bcc, $this); |
|
|
|
return $this->addHeaders('bcc: ' . $bcc); |
|
} |
|
|
|
/** |
|
* @param string $subject |
|
* @return $this |
|
*/ |
|
public function setSubject($subject) |
|
{ |
|
$this->subject = $subject; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @param string $message |
|
* @return $this |
|
*/ |
|
public function setMessage($message) |
|
{ |
|
$this->message = $message; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Sets From Email. |
|
* |
|
* @param string $from_email |
|
* |
|
* @return EP_Email |
|
*/ |
|
public function setFromEmail($from_email) |
|
{ |
|
$from_email = $this->sanitizeEmail($from_email); |
|
|
|
if (!$from_email) { |
|
throw new RuntimeException('`$from_email` should contain an email address'); |
|
} |
|
|
|
$this->from_email = apply_filters('ep.email_from_email', $from_email, $this); |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Gets From Email. |
|
* |
|
* @return string |
|
*/ |
|
public function fromEmail() |
|
{ |
|
return $this->from_email; |
|
} |
|
|
|
/** |
|
* Sets From Name. |
|
* |
|
* @param string $from_name |
|
* |
|
* @return EP_Email |
|
*/ |
|
public function setFromName($from_name) |
|
{ |
|
$from_name = sanitize_text_field($from_name); |
|
|
|
if (!$from_name) { |
|
throw new RuntimeException('`$from_name` should contain a string'); |
|
} |
|
|
|
$this->from_name = apply_filters('ep.email_from_name', $from_name, $this); |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Gets From Name. |
|
* |
|
* @return string |
|
*/ |
|
public function fromName() |
|
{ |
|
return $this->from_name; |
|
} |
|
|
|
/** |
|
* Sets an filter that helps to change the `from_email` or `from_name` |
|
*/ |
|
public function setFilterFromForMailer() |
|
{ |
|
if ($this->fromEmail()) { |
|
add_filter('wp_mail_from', [$this, 'fromEmail']); |
|
} |
|
|
|
if ($this->fromName()) { |
|
add_filter('wp_mail_from_name', [$this, 'fromName']); |
|
} |
|
} |
|
|
|
/** |
|
* Removes a filter that was meant to change `from_email` or `from_name` |
|
*/ |
|
protected function removeFilterFromForMailer() |
|
{ |
|
if ($this->fromEmail()) { |
|
remove_filter('wp_mail_from', [$this, 'fromEmail']); |
|
} |
|
|
|
if ($this->fromName()) { |
|
remove_filter('wp_mail_from_name', [$this, 'fromName']); |
|
} |
|
} |
|
|
|
/** |
|
* @param string $reply_to Comma separated list of emails |
|
* @return EP_Email |
|
*/ |
|
public function setReplyTo($reply_to) |
|
{ |
|
$reply_to = $this->sanitizeEmail($reply_to); |
|
|
|
if (!$reply_to) { |
|
throw new RuntimeException('`$reply_to` should contain an email address'); |
|
} |
|
|
|
$this->reply_to = apply_filters('ep.email_reply_to', $reply_to, $this); |
|
|
|
return $this->addHeaders('reply-to: ' . $this->reply_to); |
|
} |
|
|
|
/** |
|
* @param array $headers |
|
* @return $this |
|
*/ |
|
public function setHeaders(array $headers) |
|
{ |
|
$this->headers = $headers; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @param string $charset |
|
* @return $this |
|
*/ |
|
public function setCharset($charset) |
|
{ |
|
$this->charset = $charset; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Adds the headers |
|
* |
|
* @param $header |
|
* @return $this |
|
*/ |
|
public function addHeaders($header) |
|
{ |
|
$this->headers[] = $header; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @param array $placeholders The list of placeholders with key value pair |
|
* |
|
* Example: |
|
* [ |
|
* '{{first_name}}' => 'John', |
|
* '{{last_name}}' => 'Dou', |
|
* // ... etc |
|
* ]; |
|
* |
|
* @return $this |
|
*/ |
|
public function setPlaceholders(array $placeholders) |
|
{ |
|
$this->placeholders = $placeholders; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @return array |
|
*/ |
|
public function placeholders() |
|
{ |
|
return apply_filters('ep.email_placeholders', $this->placeholders, $this); |
|
} |
|
|
|
/** |
|
* Allow's to send ÖÕЁЙ etc letters. |
|
* |
|
* @hooked add_filter('wp_mail_charset') |
|
*/ |
|
protected function setCharsetForMailer() |
|
{ |
|
mb_internal_encoding($this->charset); |
|
|
|
add_filter('wp_mail_charset', [$this, 'encodingHelperForMailer']); |
|
} |
|
|
|
/** |
|
* Helps to restore the charset for PHPMailer; |
|
* |
|
* @hooked remove_filter('wp_mail_charset') |
|
*/ |
|
protected function restoreCharsetForMailer() |
|
{ |
|
global $phpmailer; |
|
|
|
$phpmailer->Encoding = $this->stored_php_mailer_charset; |
|
|
|
remove_filter('wp_mail_charset', [$this, 'encodingHelperForMailer']); |
|
} |
|
|
|
/** |
|
* @param WP_Error $error |
|
*/ |
|
public function performFailedAction(WP_Error $error) |
|
{ |
|
foreach ($this->failed_listeners as $listener) { |
|
$listener($this, $error); |
|
} |
|
} |
|
|
|
/** |
|
* @return $this |
|
*/ |
|
protected function setFailedListeners() |
|
{ |
|
add_action('wp_mail_failed', [$this, 'performFailedAction']); |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @return $this |
|
*/ |
|
protected function removeFailedListeners() |
|
{ |
|
remove_action('wp_mail_failed', [$this, 'performFailedAction']); |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Gather together all filters and actions that need to be performed due to send process. |
|
* |
|
* @return void |
|
*/ |
|
protected function setHelperActionsBeforeSend() |
|
{ |
|
$this->setFailedListeners(); |
|
$this->setCharsetForMailer(); |
|
$this->setFilterFromForMailer(); |
|
|
|
if (!$this->is_sent) { |
|
foreach ($this->before_send_listeners as $listener) { |
|
$listener($this); |
|
} |
|
} |
|
|
|
do_action('ep.email_before_send', $this); |
|
} |
|
|
|
/** |
|
* Remove all filters and actions after a mail being sent. |
|
* |
|
* @return void |
|
*/ |
|
protected function removeHelperActionsAfterSend() |
|
{ |
|
$this->removeFailedListeners(); |
|
$this->restoreCharsetForMailer(); |
|
$this->removeFilterFromForMailer(); |
|
|
|
if ($this->is_sent) { |
|
foreach ($this->after_sent_listeners as $listener) { |
|
$listener($this); |
|
} |
|
} |
|
|
|
do_action('ep.email_after_send', $this); |
|
} |
|
|
|
/** |
|
* @param string $blog_charset |
|
* @return string |
|
*/ |
|
public function encodingHelperForMailer($blog_charset = 'UTF-8') |
|
{ |
|
global $phpmailer; |
|
|
|
$charset = empty($this->charset) ? $blog_charset : $this->charset; |
|
|
|
$this->stored_php_mailer_charset = $phpmailer->Encoding; |
|
|
|
$phpmailer->Encoding = (!strcasecmp($charset, 'UTF-8') ? 'base64' : '8bit'); |
|
|
|
return $charset; |
|
} |
|
|
|
/** |
|
* Load an email $to. |
|
* |
|
* @return string |
|
*/ |
|
protected function to() |
|
{ |
|
return apply_filters('ep.email_to', $this->to, $this); |
|
} |
|
|
|
/** |
|
* Load an email template or return a default message. |
|
* |
|
* @return bool|false|string |
|
*/ |
|
protected function message() |
|
{ |
|
$message = nl2br(make_clickable($this->performPlaceholders($this->placeholders, $this->message))); |
|
|
|
$message = $this->charset |
|
? mb_convert_encoding($message, $this->charset, 'auto') |
|
: $message; |
|
|
|
return apply_filters('ep.email_message', $message, $this); |
|
} |
|
|
|
/** |
|
* Process the Email subject |
|
*/ |
|
protected function subject() |
|
{ |
|
return apply_filters('ep.email_subject', !empty($this->placeholders) |
|
? $this->performPlaceholders($this->placeholders, $this->subject) |
|
: $this->subject, $this); |
|
} |
|
|
|
/** |
|
* @return array |
|
*/ |
|
protected function attachments() |
|
{ |
|
return apply_filters('ep.email_attachments', array_unique($this->attachments), $this); |
|
} |
|
|
|
/** |
|
* @param array $placeholders |
|
* @param string $text |
|
* |
|
* @return mixed |
|
*/ |
|
protected function performPlaceholders(array $placeholders, $text) |
|
{ |
|
return str_replace(array_keys($placeholders), array_values($placeholders), $text); |
|
} |
|
|
|
/** |
|
* @return array |
|
*/ |
|
protected function headers() |
|
{ |
|
if ($this->charset) { |
|
$this->addHeaders("Content-Type: text/html; charset={$this->charset}"); |
|
} |
|
|
|
return apply_filters('ep.email_headers', array_unique($this->headers), $this); |
|
} |
|
|
|
/** |
|
* @param string|array $emails Comma separated email or just an array of emails. |
|
* |
|
* @return string |
|
*/ |
|
public function sanitizeEmail($emails) |
|
{ |
|
return implode( |
|
',', |
|
array_filter( |
|
array_map( |
|
'trim', |
|
is_array($emails) ? $emails : explode(',', $emails) |
|
), |
|
'is_email' |
|
) |
|
); |
|
} |
|
|
|
/** |
|
* Sends an email |
|
* |
|
* @return EP_Email |
|
*/ |
|
public function send() |
|
{ |
|
$this->setHelperActionsBeforeSend(); |
|
|
|
$email_args = [ |
|
$this->to(), |
|
$this->subject(), |
|
$this->message(), |
|
$this->headers(), |
|
$this->attachments(), |
|
]; |
|
|
|
$this->is_sent = wp_mail(... $email_args); |
|
|
|
$this->removeHelperActionsAfterSend(); |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* Sends an email when a specific action is fired. |
|
* |
|
* @param string $action |
|
* @param int $priority |
|
* |
|
* @return EP_Email |
|
*/ |
|
public function sendWhen($action, $priority = 10) |
|
{ |
|
if (!did_action($action)) { |
|
add_action($action, [$this, 'send'], $priority); |
|
} |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @param Closure $cb |
|
* @return $this |
|
*/ |
|
public function beforeSend(Closure $cb) { |
|
$this->before_send_listeners[] = $cb; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @param Closure $cb |
|
* @return $this |
|
*/ |
|
public function afterSent(Closure $cb) |
|
{ |
|
$this->after_sent_listeners[] = $cb; |
|
|
|
return $this; |
|
} |
|
|
|
/** |
|
* @param Closure $cb |
|
* @return $this |
|
*/ |
|
public function ifFailed(Closure $cb) |
|
{ |
|
$this->failed_listeners[] = $cb; |
|
|
|
return $this; |
|
} |
|
} |