Skip to content

Commit

Permalink
Mailer: Change FromAddress to EmailAddress object + Spoofing
Browse files Browse the repository at this point in the history
This commit refactors how FROM address is set and used within the Mailer. It's
now set as EmailAddress object - making it easy to get Email and Name
separately.

We're also removing Spoofing Check when determining possible SMTP accounts to
use for outgoing emails. It's now checked while attempting to send a Message.
If the account in question doesn't allow Spoofing then the FROM header is reset
to the accounts email address.
  • Loading branch information
protich committed Sep 23, 2022
1 parent 551f786 commit d7d37c4
Showing 1 changed file with 53 additions and 30 deletions.
83 changes: 53 additions & 30 deletions include/class.mailer.php
Expand Up @@ -18,6 +18,7 @@ class.mailer.php
namespace osTicket\Mail;

class Mailer {
private $from = null;
var $email = null;
var $accounts = [];

Expand All @@ -35,18 +36,18 @@ function __construct(\Email $email=null, array $options=array()) {
&& $smtp->isActive()) {
$this->accounts[$smtp->getId()] = $smtp;
}

if ($cfg
&& ($smtp=$cfg->getDefaultMTA())
&& $smtp->isActive()) {
$this->accounts[$smtp->getId()] = $smtp;
if ($smtp->allowSpoofing() || !$email)
$email = $smtp->getEmail();
}

if (!$email && $cfg && ($email=$cfg->getDefaultEmail())) {
if (($smtp=$email->getSmtpAccount(false)) && $smtp->isActive())
if ($cfg) {
// Get Default MTA (SMTP)
if (($smtp=$cfg->getDefaultMTA()) && $smtp->isActive()) {
$this->accounts[$smtp->getId()] = $smtp;
// If email is not set then use Default MTA
if (!$email)
$email = $smtp->getEmail();
} elseif (!$email && $cfg && ($email=$cfg->getDefaultEmail())) {
// as last resort we will send via Default Email
if (($smtp=$email->getSmtpAccount(false)) && $smtp->isActive())
$this->accounts[$smtp->getId()] = $smtp;
}
}

$this->email = $email;
Expand All @@ -71,20 +72,36 @@ function getEmail() {
}

/* FROM Address */
function setFromAddress($from) {
$this->ht['from'] = $from;
function setFromAddress($from=null, $name=null) {
if ($from instanceof \EmailAddress)
$this->from = $from;
elseif (\Validator::is_email($from)) {
$this->from = new \EmailAddress(
sprintf('"%s" <%s>', $name ?: '', $from));
} elseif (is_string($from))
$this->from = new \EmailAddress($from);
elseif (($email=$this->getEmail())) {
// we're assuming from was null or unexpected monster
$address = sprintf('"%s" <%s>',
$name ?: $email->getName(),
$email->getEmail());
$this->from = new \EmailAddress($address);
}
}

function getFromAddress($options=array()) {
if (!isset($this->from))
$this->setFromAddress(null, $options['from_name'] ?: null);

if (!$this->ht['from'] && ($email=$this->getEmail())) {
if (($name = $options['from_name'] ?: $email->getName()))
$this->ht['from'] =sprintf('"%s" <%s>', $name, $email->getEmail());
else
$this->ht['from'] =sprintf('<%s>', $email->getEmail());
}
return $this->from;
}

return $this->ht['from'];
function getFromName() {
return $this->getFromAddress()->getName();
}

function getFromEmail() {
return $this->getFromAddress()->getEmail();
}

/* attachments */
Expand Down Expand Up @@ -323,8 +340,10 @@ function send($recipients, $subject, $body, $options=null) {

// Create new ostTicket/Mail/Message object
$message = new Message();
// Set basic headers
$message->addFrom($this->getFromAddress($options));
// Set From Address
$from = $this->getFromAddress($options);
$message->setFrom($from->getEmail(), $from->getName());
// Set Subject
$message->setSubject($subject);

$headers = array (
Expand Down Expand Up @@ -507,7 +526,7 @@ class="mid-%s">%s</div>%s',
if ($isHtml && $cfg && $cfg->isRichTextEnabled()) {
// Pick a domain compatible with pear Mail_Mime
$matches = array();
if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', $this->getFromAddress(), $matches)) {
if (preg_match('#(@[0-9a-zA-Z\-\.]+)#', (string) $this->getFromAddress(), $matches)) {
$domain = $matches[1];
} else {
$domain = '@localhost';
Expand Down Expand Up @@ -556,13 +575,17 @@ function($match) use ($domain, $message, $self) {
}
}

// set Body & Content Type
$message->prepare();

// Try possible SMTP Accounts - connections are cached per request
// at the account level.
foreach ($this->getSmtpAccounts() ?: [] as $account) {
try {
// Overwrite FROM Address if the account doesn't allow spoofing
if (!$account->allowSpoofing())
$message->setFrom(
// get Account Email
(string) $account->getEmail()->getEmail(),
// Try to keep the name if available
$this->getFromName() ?: $account->getName());
if (($smtp=$account->getSmtpConnection())
&& $smtp->sendMessage($message))
return $messageId;
Expand All @@ -583,8 +606,8 @@ function($match) use ($domain, $message, $self) {
$args = [];
if (isset($options['from_address']))
$args[] = '-f '.$options['from_address'];
elseif ($this->getEmail())
$args = ['-f '.$this->getEmail()->getEmail()];
elseif (($from=$this->getFromAddress()))
$args = ['-f '.$from->getEmail()];

try {
// ostTicket/Mail/Sendmail transport
Expand Down Expand Up @@ -628,9 +651,9 @@ function logWarning($warning) {

//Emails using native php mail function - if DB connection doesn't exist.
//Don't use this function if you can help it.
static function sendmail($to, $subject, $message, $from, $options=null) {
static function sendmail($to, $subject, $message, $from=null, $options=null) {
$mailer = new Mailer(null, array('notice'=>true, 'nobounce'=>true));
$mailer->setFromAddress($from);
$mailer->setFromAddress($from, $options['from_name'] ?: null);
return $mailer->send($to, $subject, $message, $options);
}
}

0 comments on commit d7d37c4

Please sign in to comment.