Clean up and formatting for mailers

This commit is contained in:
David Bomba 2023-01-15 21:16:10 +11:00
parent 7c3aaa4898
commit d1049f3a90
5 changed files with 199 additions and 43 deletions

View File

@ -32,8 +32,6 @@ class CheckMailRequest extends Request
*/
public function rules()
{
nlog($this->driver);
return [
'mail_driver' => 'required',
'encryption' => 'required_unless:mail_driver,log',

View File

@ -24,14 +24,36 @@ use Illuminate\Mail\Attachment;
class EmailDefaults
{
/**
* The settings object for this email
* @var CompanySettings $settings
*/
protected $settings;
/**
* The HTML / Template to use for this email
* @var string $template
*/
private string $template;
/**
* The locale to use for
* translations for this email
*/
private string $locale;
/**
* @param EmailService $email_service The email service class
* @param EmailObject $email_object the email object class
*/
public function __construct(protected EmailService $email_service, public EmailObject $email_object){}
/**
* Entry point for generating
* the defaults for the email object
*
* @return EmailObject $email_object The email object
*/
public function run()
{
$this->settings = $this->email_object->settings;
@ -51,6 +73,9 @@ class EmailDefaults
}
/**
* Sets the meta data for the Email object
*/
private function setMetaData(): self
{
@ -66,6 +91,9 @@ class EmailDefaults
}
/**
* Sets the locale
*/
private function setLocale(): self
{
@ -84,6 +112,9 @@ class EmailDefaults
return $this;
}
/**
* Sets the template
*/
private function setTemplate(): self
{
$this->template = $this->email_object->settings->email_style;
@ -100,6 +131,9 @@ class EmailDefaults
return $this;
}
/**
* Sets the FROM address
*/
private function setFrom(): self
{
if($this->email_object->from)
@ -111,7 +145,9 @@ class EmailDefaults
}
//think about where we do the string replace for variables....
/**
* Sets the body of the email
*/
private function setBody(): self
{
@ -133,7 +169,9 @@ class EmailDefaults
}
//think about where we do the string replace for variables....
/**
* Sets the subject of the email
*/
private function setSubject(): self
{
@ -148,6 +186,25 @@ class EmailDefaults
}
/**
* Sets the reply to of the email
*/
private function setReplyTo(): self
{
$reply_to_email = str_contains($this->email_object->settings->reply_to_email, "@") ? $this->email_object->settings->reply_to_email : $this->email_service->company->owner()->email;
$reply_to_name = strlen($this->email_object->settings->reply_to_name) > 3 ? $this->email_object->settings->reply_to_name : $this->email_service->company->owner()->present()->name();
$this->email_object->reply_to = array_merge($this->email_object->reply_to, [new Address($reply_to_email, $reply_to_name)]);
return $this;
}
/**
* Replaces the template placeholders
* with variable values.
*/
public function setVariables(): self
{
@ -161,18 +218,9 @@ class EmailDefaults
return $this;
}
private function setReplyTo(): self
{
$reply_to_email = str_contains($this->email_object->settings->reply_to_email, "@") ? $this->email_object->settings->reply_to_email : $this->email_service->company->owner()->email;
$reply_to_name = strlen($this->email_object->settings->reply_to_name) > 3 ? $this->email_object->settings->reply_to_name : $this->email_service->company->owner()->present()->name();
$this->email_object->reply_to = array_merge($this->email_object->reply_to, [new Address($reply_to_email, $reply_to_name)]);
return $this;
}
/**
* Sets the BCC of the email
*/
private function setBcc(): self
{
$bccs = [];
@ -197,6 +245,10 @@ class EmailDefaults
return $this;
}
/**
* Sets the CC of the email
* @todo at some point....
*/
private function buildCc()
{
return [
@ -204,6 +256,14 @@ class EmailDefaults
];
}
/**
* Sets the attachments for the email
*
* Note that we base64 encode these, as they
* sometimes may not survive serialization.
*
* We decode these in the Mailable later
*/
private function setAttachments(): self
{
$attachments = [];
@ -224,6 +284,9 @@ class EmailDefaults
}
/**
* Sets the headers for the email
*/
private function setHeaders(): self
{
if($this->email_object->invitation_key)
@ -232,7 +295,13 @@ class EmailDefaults
return $this;
}
public function parseMarkdownToHtml(string $markdown): ?string
/**
* Converts any markdown to HTML in the email
*
* @param string $markdown The body to convert
* @return string The parsed markdown response
*/
private function parseMarkdownToHtml(string $markdown): ?string
{
$converter = new CommonMarkConverter([
'allow_unsafe_links' => false,

View File

@ -59,7 +59,7 @@ class EmailMailable extends Mailable
view: $this->email_object->template,
text: $this->email_object->text_template,
with: [
'text_body' => strip_tags($this->email_object->body),
'text_body' => strip_tags($this->email_object->body), //@todo this is a bit hacky here.
'body' => $this->email_object->body,
'settings' => $this->email_object->settings,
'whitelabel' => $this->email_object->whitelabel,

View File

@ -71,26 +71,28 @@ class EmailMailer implements ShouldQueue
{
MultiDB::setDb($this->email_service->company->db);
//decode all attachments
/* Perform final checks */
if($this->email_service->preFlightChecksFail())
return;
/* Boot the required driver*/
$this->setMailDriver();
/* Init the mailer*/
$mailer = Mail::mailer($this->mailer);
if($this->client_postmark_secret){
nlog("inside postmark config");
nlog($this->client_postmark_secret);
/* Additional configuration if using a client third party mailer */
if($this->client_postmark_secret)
$mailer->postmark_config($this->client_postmark_secret);
}
if($this->client_mailgun_secret){
if($this->client_mailgun_secret)
$mailer->mailgun_config($this->client_mailgun_secret, $this->client_mailgun_domain);
}
//send email
/* Attempt the send! */
try {
nlog("Using mailer => ". $this->mailer. " ". now()->toDateTimeString());
$mailer->send($this->email_mailable);
Cache::increment($this->email_service->company->account->key);
@ -131,16 +133,15 @@ class EmailMailer implements ShouldQueue
app('sentry')->captureException($e);
$message = null;
// $this->email_service = null;
// $this->email_mailable = null;
}
}
/**
* Entity notification when an email fails to send
*
*
* @todo - rewrite this
* @param string $message
* @return void
*/
@ -171,6 +172,10 @@ class EmailMailer implements ShouldQueue
}
/**
* Sets the mail driver to use and applies any specific configuration
* the the mailable
*/
private function setMailDriver(): self
{
@ -263,9 +268,10 @@ class EmailMailer implements ShouldQueue
private function checkValidSendingUser($user)
{
/* Always ensure the user is set on the correct account */
if($user->account_id != $this->email_service->company->account_id){
if($user->account_id != $this->email_service->company->account_id)
{
$this->email_service->email_object->settings->email_sending_method = 'default';
return $this->setMailDriver();
}
}
@ -281,11 +287,13 @@ class EmailMailer implements ShouldQueue
{
$sending_user = $this->email_service->email_object->settings->gmail_sending_user_id;
$user = User::find($this->decodePrimaryKey($sending_user));
if($sending_user == "0")
$user = $this->email_service->company->owner();
else
$user = User::find($this->decodePrimaryKey($sending_user));
return $user;
}
/**
* Configures Mailgun using client supplied secret
* as the Mailer
@ -301,7 +309,6 @@ class EmailMailer implements ShouldQueue
return $this->setMailDriver();
}
$user = $this->resolveSendingUser();
$this->mailable
@ -462,9 +469,9 @@ class EmailMailer implements ShouldQueue
* Attempts to refresh the Microsoft refreshToken
*
* @param App\Models\User
* @return string | bool
* @return mixed
*/
private function refreshOfficeToken($user)
private function refreshOfficeToken(User $user): mixed
{
$expiry = $user->oauth_user_token_expiry ?: now()->subDay();

View File

@ -13,18 +13,28 @@ namespace App\Services\Email;
use App\Models\Company;
use App\Services\Email\EmailObject;
use App\Utils\Ninja;
use Illuminate\Mail\Mailable;
class EmailService
{
protected string $mailer;
/**
* Used to flag whether we force send the email regardless
*
* @var bool $override;
*/
protected bool $override;
public Mailable $mailable;
public function __construct(public EmailObject $email_object, public Company $company){}
/**
* Sends the email via a dispatched job
* @param boolean $override Whether the email should send regardless
* @return void
*/
public function send($override = false) :void
{
$this->override = $override;
@ -34,11 +44,11 @@ class EmailService
->email();
}
public function sendNow($override = false) :void
public function sendNow($force = false) :void
{
$this->setDefaults()
->updateMailable()
->email(true);
->email($force);
}
private function email($force = false): void
@ -65,9 +75,81 @@ class EmailService
return $this;
}
private function emailQualityCheck()
/**
* On the hosted platform we scan all outbound email for
* spam. This sequence processes the filters we use on all
* emails.
*
* @return bool
*/
public function preFlightChecksFail(): bool
{
/* If we are migrating data we don't want to fire any emails */
if($this->company->is_disabled && !$this->override)
return true;
/* To handle spam users we drop all emails from flagged accounts */
if(Ninja::isHosted() && $this->company->account && $this->company->account->is_flagged)
return true;
/* On the hosted platform we set default contacts a @example.com email address - we shouldn't send emails to these types of addresses */
if(Ninja::isHosted() && $this->hasValidEmails())
return true;
/* GMail users are uncapped */
if(Ninja::isHosted() && in_array($this->email_object->settings->email_sending_method, ['gmail', 'office365', 'client_postmark', 'client_mailgun']))
return false;
/* On the hosted platform, if the user is over the email quotas, we do not send the email. */
if(Ninja::isHosted() && $this->company->account && $this->company->account->emailQuotaExceeded())
return true;
/* If the account is verified, we allow emails to flow */
if(Ninja::isHosted() && $this->company->account && $this->company->account->is_verified_account) {
//11-01-2022
/* Continue to analyse verified accounts in case they later start sending poor quality emails*/
// if(class_exists(\Modules\Admin\Jobs\Account\EmailQuality::class))
// (new \Modules\Admin\Jobs\Account\EmailQuality($this->nmo, $this->company))->run();
return false;
}
/* On the hosted platform if the user has not verified their account we fail here - but still check what they are trying to send! */
if(Ninja::isHosted() && $this->company->account && !$this->company->account->account_sms_verified){
if(class_exists(\Modules\Admin\Jobs\Account\EmailFilter::class))
return (new \Modules\Admin\Jobs\Account\EmailFilter($this->email_object, $this->company))->run();
return true;
}
/* On the hosted platform we actively scan all outbound emails to ensure outbound email quality remains high */
if(class_exists(\Modules\Admin\Jobs\Account\EmailFilter::class))
return (new \Modules\Admin\Jobs\Account\EmailFilter($this->email_object, $this->company))->run();
return false;
}
private function hasValidEmails(): bool
{
foreach($this->email_object->to as $address_object)
{
if(strpos($address_object->address, '@example.com') !== false)
return true;
if(!str_contains($address_object->address, "@"))
return true;
}
return false;
}
}