mirror of
				https://github.com/invoiceninja/invoiceninja.git
				synced 2025-11-03 22:47:32 -05:00 
			
		
		
		
	Refactor for emails
This commit is contained in:
		
							parent
							
								
									e75954b5c8
								
							
						
					
					
						commit
						4670c06b7e
					
				
							
								
								
									
										157
									
								
								app/Services/Email/BaseMailer.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								app/Services/Email/BaseMailer.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,157 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Services\Email;
 | 
			
		||||
 | 
			
		||||
use App\Libraries\MultiDB;
 | 
			
		||||
use App\Models\Company;
 | 
			
		||||
use App\Services\Email\MailBuild;
 | 
			
		||||
use App\Utils\Ninja;
 | 
			
		||||
use Illuminate\Bus\Queueable;
 | 
			
		||||
use Illuminate\Contracts\Queue\ShouldQueue;
 | 
			
		||||
use Illuminate\Foundation\Bus\Dispatchable;
 | 
			
		||||
use Illuminate\Queue\InteractsWithQueue;
 | 
			
		||||
use Illuminate\Queue\SerializesModels;
 | 
			
		||||
 | 
			
		||||
class BaseMailer implements ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    protected Company $company;
 | 
			
		||||
 | 
			
		||||
    public int $tries = 4;
 | 
			
		||||
 | 
			
		||||
    public ?string $client_postmark_secret = false;
 | 
			
		||||
 | 
			
		||||
    public ?string $client_mailgun_secret = null;
 | 
			
		||||
 | 
			
		||||
    public ?string $client_mailgun_domain = null;
 | 
			
		||||
 | 
			
		||||
    public boolean $override = false;
 | 
			
		||||
 | 
			
		||||
    public $deleteWhenMissingModels = true;
 | 
			
		||||
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function handle(MailBuild $builder): void
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function companyCheck()
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
        /* Handle bad state */
 | 
			
		||||
        if(!$this->company)
 | 
			
		||||
            $this->fail();
 | 
			
		||||
 | 
			
		||||
        /* Handle deactivated company */
 | 
			
		||||
        if($this->company->is_disabled && !$this->override) 
 | 
			
		||||
            $this->fail();
 | 
			
		||||
 | 
			
		||||
        /* To handle spam users we drop all emails from flagged accounts */
 | 
			
		||||
        if(Ninja::isHosted() && $this->company->account && $this->company->account->is_flagged) 
 | 
			
		||||
            $this->fail();
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function configureMailer(): self
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        return $this;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function trySending()
 | 
			
		||||
    {
 | 
			
		||||
           try {
 | 
			
		||||
 | 
			
		||||
            $mailer
 | 
			
		||||
                ->to($this->nmo->to_user->email)
 | 
			
		||||
                ->send($this->nmo->mailable);
 | 
			
		||||
 | 
			
		||||
            /* Count the amount of emails sent across all the users accounts */
 | 
			
		||||
            Cache::increment($this->company->account->key);
 | 
			
		||||
 | 
			
		||||
            LightLogs::create(new EmailSuccess($this->company->company_key))
 | 
			
		||||
                     ->send();
 | 
			
		||||
 | 
			
		||||
         }
 | 
			
		||||
        catch(\Symfony\Component\Mime\Exception\RfcComplianceException $e) {
 | 
			
		||||
                nlog("Mailer failed with a Logic Exception {$e->getMessage()}");
 | 
			
		||||
                $this->fail();
 | 
			
		||||
                $this->cleanUpMailers();
 | 
			
		||||
                $this->logMailError($e->getMessage(), $this->company->clients()->first());
 | 
			
		||||
                return;
 | 
			
		||||
        }
 | 
			
		||||
        catch(\Symfony\Component\Mime\Exception\LogicException $e){
 | 
			
		||||
                nlog("Mailer failed with a Logic Exception {$e->getMessage()}");
 | 
			
		||||
                $this->fail();
 | 
			
		||||
                $this->cleanUpMailers();
 | 
			
		||||
                $this->logMailError($e->getMessage(), $this->company->clients()->first());
 | 
			
		||||
                return;
 | 
			
		||||
        }
 | 
			
		||||
        catch (\Exception | \Google\Service\Exception $e) {
 | 
			
		||||
            
 | 
			
		||||
            nlog("Mailer failed with {$e->getMessage()}");
 | 
			
		||||
            $message = $e->getMessage();
 | 
			
		||||
 | 
			
		||||
            /**
 | 
			
		||||
             * Post mark buries the proper message in a a guzzle response
 | 
			
		||||
             * this merges a text string with a json object
 | 
			
		||||
             * need to harvest the ->Message property using the following
 | 
			
		||||
             */
 | 
			
		||||
            if(stripos($e->getMessage(), 'code 406') || stripos($e->getMessage(), 'code 300') || stripos($e->getMessage(), 'code 413')) 
 | 
			
		||||
            { 
 | 
			
		||||
 | 
			
		||||
                $message = "Either Attachment too large, or recipient has been suppressed.";
 | 
			
		||||
 | 
			
		||||
                $this->fail();
 | 
			
		||||
                $this->logMailError($e->getMessage(), $this->company->clients()->first());
 | 
			
		||||
                $this->cleanUpMailers();
 | 
			
		||||
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            //only report once, not on all tries
 | 
			
		||||
            if($this->attempts() == $this->tries)
 | 
			
		||||
            {
 | 
			
		||||
 | 
			
		||||
                /* If the is an entity attached to the message send a failure mailer */
 | 
			
		||||
                if($this->nmo->entity)
 | 
			
		||||
                    $this->entityEmailFailed($message);
 | 
			
		||||
 | 
			
		||||
                /* Don't send postmark failures to Sentry */
 | 
			
		||||
                if(Ninja::isHosted() && (!$e instanceof ClientException)) 
 | 
			
		||||
                    app('sentry')->captureException($e);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
        
 | 
			
		||||
            /* Releasing immediately does not add in the backoff */
 | 
			
		||||
            $this->release($this->backoff()[$this->attempts()-1]);
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function backoff()
 | 
			
		||||
    {
 | 
			
		||||
        return [5, 10, 30, 240];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function failed($exception = null)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        config(['queue.failed.driver' => null]);
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
`
 | 
			
		||||
							
								
								
									
										22
									
								
								app/Services/Email/MailBuild.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								app/Services/Email/MailBuild.php
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
<?php
 | 
			
		||||
/**
 | 
			
		||||
 * Invoice Ninja (https://invoiceninja.com).
 | 
			
		||||
 *
 | 
			
		||||
 * @link https://github.com/invoiceninja/invoiceninja source repository
 | 
			
		||||
 *
 | 
			
		||||
 * @copyright Copyright (c) 2023. Invoice Ninja LLC (https://invoiceninja.com)
 | 
			
		||||
 *
 | 
			
		||||
 * @license https://www.elastic.co/licensing/elastic-license
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
namespace App\Services\Email;
 | 
			
		||||
 | 
			
		||||
class MailBuild
 | 
			
		||||
{
 | 
			
		||||
    
 | 
			
		||||
    public function __construct()
 | 
			
		||||
    {
 | 
			
		||||
        
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
@ -13,52 +13,50 @@ namespace App\Services\Email;
 | 
			
		||||
 | 
			
		||||
use App\Libraries\MultiDB;
 | 
			
		||||
use App\Models\Company;
 | 
			
		||||
use App\Services\Email\MailBuild;
 | 
			
		||||
use Illuminate\Bus\Queueable;
 | 
			
		||||
use Illuminate\Contracts\Queue\ShouldQueue;
 | 
			
		||||
use Illuminate\Foundation\Bus\Dispatchable;
 | 
			
		||||
use Illuminate\Queue\InteractsWithQueue;
 | 
			
		||||
use Illuminate\Queue\SerializesModels;
 | 
			
		||||
 | 
			
		||||
class MailEntity implements ShouldQueue
 | 
			
		||||
class MailEntity extends BaseMailer implements ShouldQueue
 | 
			
		||||
{
 | 
			
		||||
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
 | 
			
		||||
 | 
			
		||||
    protected Company $company;
 | 
			
		||||
 | 
			
		||||
    public function __construct(protected $invitation, private ?string $db, private ?string $reminder_template = null, private ?string $template_data = null, private bool $override = false)
 | 
			
		||||
    public function __construct(protected $invitation, private ?string $db, public MailObject $mail_object)
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        $this->invitation = $invitation;
 | 
			
		||||
 | 
			
		||||
        $this->company = $invitation->company;
 | 
			
		||||
 | 
			
		||||
        $this->db = $db;
 | 
			
		||||
 | 
			
		||||
        $this->reminder_template = $reminder_template;
 | 
			
		||||
        $this->mail_object = $mail_object;
 | 
			
		||||
 | 
			
		||||
        $this->template_data = $template_data;
 | 
			
		||||
 | 
			
		||||
        $this->override = $override;
 | 
			
		||||
 | 
			
		||||
        // $this->entity_string = $this->resolveEntityString();
 | 
			
		||||
 | 
			
		||||
        // $this->entity = $invitation->{$this->entity_string};
 | 
			
		||||
 | 
			
		||||
        // $this->settings = $invitation->contact->client->getMergedSettings();
 | 
			
		||||
 | 
			
		||||
        // $this->reminder_template = $reminder_template ?: $this->entity->calculateTemplate($this->entity_string);
 | 
			
		||||
 | 
			
		||||
        // $this->html_engine = new HtmlEngine($invitation);
 | 
			
		||||
 | 
			
		||||
        // $this->template_data = $template_data;
 | 
			
		||||
        $this->override = $mail_object->override;
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function handle(): void
 | 
			
		||||
    public function handle(MailBuild $builder): void
 | 
			
		||||
    {
 | 
			
		||||
        MultiDB::setDb($this->db);
 | 
			
		||||
 | 
			
		||||
        $this->companyCheck();
 | 
			
		||||
 | 
			
		||||
        //construct mailable
 | 
			
		||||
 | 
			
		||||
        //spam checks
 | 
			
		||||
 | 
			
		||||
        //what do we pass into a generaic builder?
 | 
			
		||||
        
 | 
			
		||||
        //construct mailer
 | 
			
		||||
        $mailer = $this->configureMailer()
 | 
			
		||||
                       ->trySending();
 | 
			
		||||
 | 
			
		||||
     
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -77,4 +77,11 @@ class MailObject
 | 
			
		||||
 | 
			
		||||
	public array $variables = [];
 | 
			
		||||
	
 | 
			
		||||
	public ?string $reminder_template = null;
 | 
			
		||||
 | 
			
		||||
	public ?string $template_data = null;
 | 
			
		||||
 | 
			
		||||
	public bool $override = false;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user