Initial commit
This commit is contained in:
130
app/Mail/BounceAwarePendingMail.php
Normal file
130
app/Mail/BounceAwarePendingMail.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
namespace App\Mail;
|
||||
|
||||
use App\Models\MailingBounce;
|
||||
use Illuminate\Mail\PendingMail;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BounceAwarePendingMail extends PendingMail
|
||||
{
|
||||
/**
|
||||
* Send a new mailable message instance with bounce checking
|
||||
*/
|
||||
public function send($mailable)
|
||||
{
|
||||
// Filter out suppressed recipients before sending
|
||||
$this->filterSuppressedRecipients();
|
||||
|
||||
// If no valid recipients remain, don't send
|
||||
if (empty($this->to) && empty($this->cc) && empty($this->bcc)) {
|
||||
Log::info("All recipients suppressed, skipping email send", [
|
||||
'mailable_class' => get_class($mailable)
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add bounce tracking headers if the mailable supports it
|
||||
if (method_exists($mailable, 'configureBounceTracking') || $this->usesBounceTrackingTrait($mailable)) {
|
||||
$this->addBounceTrackingToMailable($mailable);
|
||||
}
|
||||
|
||||
return parent::send($mailable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue a new e-mail message for sending with bounce checking
|
||||
*/
|
||||
public function queue($mailable)
|
||||
{
|
||||
// Filter out suppressed recipients before queuing
|
||||
$this->filterSuppressedRecipients();
|
||||
|
||||
// If no valid recipients remain, don't queue
|
||||
if (empty($this->to) && empty($this->cc) && empty($this->bcc)) {
|
||||
Log::info("All recipients suppressed, skipping email queue", [
|
||||
'mailable_class' => get_class($mailable)
|
||||
]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Add bounce tracking headers if the mailable supports it
|
||||
if (method_exists($mailable, 'configureBounceTracking') || $this->usesBounceTrackingTrait($mailable)) {
|
||||
$this->addBounceTrackingToMailable($mailable);
|
||||
}
|
||||
|
||||
return parent::queue($mailable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out suppressed email addresses from recipients
|
||||
*/
|
||||
protected function filterSuppressedRecipients(): void
|
||||
{
|
||||
$this->to = $this->filterRecipientList($this->to);
|
||||
$this->cc = $this->filterRecipientList($this->cc);
|
||||
$this->bcc = $this->filterRecipientList($this->bcc);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter a specific recipient list
|
||||
*/
|
||||
protected function filterRecipientList(array $recipients): array
|
||||
{
|
||||
$filtered = [];
|
||||
|
||||
foreach ($recipients as $recipient) {
|
||||
$email = $this->extractEmailAddress($recipient);
|
||||
|
||||
if ($email && MailingBounce::isSuppressed($email)) {
|
||||
Log::info("Email sending blocked for suppressed address: {$email}", [
|
||||
'suppressed' => true
|
||||
]);
|
||||
continue;
|
||||
}
|
||||
|
||||
$filtered[] = $recipient;
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract email address from recipient
|
||||
*/
|
||||
protected function extractEmailAddress($recipient): ?string
|
||||
{
|
||||
if (is_string($recipient)) {
|
||||
return $recipient;
|
||||
}
|
||||
|
||||
if (is_array($recipient)) {
|
||||
return $recipient['address'] ?? null;
|
||||
}
|
||||
|
||||
if (is_object($recipient)) {
|
||||
return $recipient->email ?? null;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if mailable uses the bounce tracking trait
|
||||
*/
|
||||
protected function usesBounceTrackingTrait($mailable): bool
|
||||
{
|
||||
return in_array('App\Mail\Concerns\TracksBounces', class_uses_recursive($mailable));
|
||||
}
|
||||
|
||||
/**
|
||||
* Add bounce tracking to mailable
|
||||
*/
|
||||
protected function addBounceTrackingToMailable($mailable): void
|
||||
{
|
||||
// Mark that bounce tracking should be enabled
|
||||
if (property_exists($mailable, 'bounceTrackingEnabled')) {
|
||||
$mailable->bounceTrackingEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user