Skip to content

Commit

Permalink
Merge pull request #29 from vormkracht10/feature/suppressions-list
Browse files Browse the repository at this point in the history
Suppressions list
  • Loading branch information
arduinomaster22 authored Jan 23, 2025
2 parents 4e8ef97 + e8dfdf7 commit 301f18b
Show file tree
Hide file tree
Showing 10 changed files with 124 additions and 2 deletions.
29 changes: 29 additions & 0 deletions database/migrations/3_add_unsuppressed_at_to_mail_events.php.stub
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::table('mail_events', function (Blueprint $table): void {
$table->timestamp('unsuppressed_at')
->nullable()
->after('occurred_at');
});

Schema::table('mails', function (Blueprint $table): void {
$table->string('mailer')
->after('uuid');

$table->string('stream_id')
->nullable()
->after('mailer');
});
}
};
17 changes: 16 additions & 1 deletion src/Actions/LogMail.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,12 +74,27 @@ public function getDefaultLogAttributes(MessageSending|MessageSent $event): arra
];
}

protected function getStreamId(MessageSending|MessageSent $event): ?string
{
if ($event->data['mailer'] !== 'postmark') {
return null;
}

if (null !== $messageStream = $event->message->getHeaders()->get('x-pm-message-stream')) {
return $messageStream;

Check failure on line 84 in src/Actions/LogMail.php

View workflow job for this annotation

GitHub Actions / phpstan

Method Vormkracht10\Mails\Actions\LogMail::getStreamId() should return string|null but returns Symfony\Component\Mime\Header\HeaderInterface.

Check failure on line 84 in src/Actions/LogMail.php

View workflow job for this annotation

GitHub Actions / phpstan

Method Vormkracht10\Mails\Actions\LogMail::getStreamId() should return string|null but returns Symfony\Component\Mime\Header\HeaderInterface.
}

return config('mail.mailers.postmark.message_stream_id', 'outbound');
}

public function getMandatoryAttributes(MessageSending|MessageSent $event): array
{
return [
'uuid' => $this->getCustomUuid($event),
// 'mail_class' => $this->getMailClassHeaderValue($event),
'sent_at' => $event instanceof MessageSent ? now() : null,
'mailer' => $event->data['mailer'],
'stream_id' => $this->getStreamId($event),
];
}

Expand All @@ -101,7 +116,7 @@ protected function getCustomUuid(MessageSending|MessageSent $event): ?string
protected function getAddressesValue(array $address): ?Collection
{
$addresses = collect($address)
->flatMap(fn(Address $address) => [$address->getAddress() => $address->getName() === '' ? null : $address->getName()]);
->flatMap(fn (Address $address) => [$address->getAddress() => $address->getName() === '' ? null : $address->getName()]);

return $addresses->count() > 0 ? $addresses : null;
}
Expand Down
12 changes: 11 additions & 1 deletion src/Drivers/MailgunDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Vormkracht10\Mails\Drivers;

use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\URL;
use Vormkracht10\Mails\Contracts\MailDriverContract;
Expand Down Expand Up @@ -78,7 +79,7 @@ public function verifyWebhookSignature(array $payload): bool
return false;
}

$hmac = hash_hmac('sha256', $payload['signature']['timestamp'] . $payload['signature']['token'], config('services.mailgun.webhook_signing_key'));
$hmac = hash_hmac('sha256', $payload['signature']['timestamp'].$payload['signature']['token'], config('services.mailgun.webhook_signing_key'));

if (function_exists('hash_equals')) {
return hash_equals($hmac, $payload['signature']['signature']);
Expand Down Expand Up @@ -127,4 +128,13 @@ public function dataMapping(): array
'tag' => 'tags',
];
}

public function unsuppressEmailAddress(string $address): Response
{
$client = Http::asJson()
->withBasicAuth('api', config('services.mailgun.secret'))
->baseUrl(config('services.mailgun.endpoint').'/v3/');

return $client->delete(config('services.mailgun.domain').'/unsubscribes/'.$address);
}
}
19 changes: 19 additions & 0 deletions src/Drivers/PostmarkDriver.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Vormkracht10\Mails\Drivers;

use Illuminate\Http\Client\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\URL;
use Vormkracht10\Mails\Contracts\MailDriverContract;
Expand Down Expand Up @@ -139,4 +140,22 @@ public function dataMapping(): array
'user_agent' => 'UserAgent',
];
}

public function unsuppressEmailAddress(string $address, $stream_id): Response
{
$client = Http::asJson()
->withHeaders([
'X-Postmark-Server-Token' => config('services.postmark.token'),
])
->baseUrl('https://api.postmarkapp.com/');

return $client->post('message-streams/'.$stream_id.'/suppressions/delete', [
'Suppressions' => [
[
'emailAddress' => $address,
],
],
]);

}
}
17 changes: 17 additions & 0 deletions src/Events/MailUnsuppressed.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php

namespace Vormkracht10\Mails\Events;

use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class MailUnsuppressed
{
use Dispatchable, InteractsWithSockets, SerializesModels;

/**
* Create a new event instance.
*/
public function __construct(public string $emailAddress, public string $mailer, public ?string $stream_id = null) {}
}
18 changes: 18 additions & 0 deletions src/Listeners/UnsuppressEmailAddress.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Vormkracht10\Mails\Listeners;

use Vormkracht10\Mails\Events\MailUnsuppressed;
use Vormkracht10\Mails\Facades\MailProvider;

class UnsuppressEmailAddress
{
public function handle(MailUnsuppressed $event): void
{
MailProvider::with(driver: $event->mailer)

Check failure on line 12 in src/Listeners/UnsuppressEmailAddress.php

View workflow job for this annotation

GitHub Actions / phpstan

Call to an undefined method Vormkracht10\Mails\Contracts\MailDriverContract::unsuppressEmailAddress().

Check failure on line 12 in src/Listeners/UnsuppressEmailAddress.php

View workflow job for this annotation

GitHub Actions / phpstan

Call to an undefined method Vormkracht10\Mails\Contracts\MailDriverContract::unsuppressEmailAddress().
->unsuppressEmailAddress(
address: $event->emailAddress,
stream_id: $event->stream_id ?? null
);
}
}
5 changes: 5 additions & 0 deletions src/MailsServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,14 @@
use Vormkracht10\Mails\Contracts\MailProviderContract;
use Vormkracht10\Mails\Events\MailEvent;
use Vormkracht10\Mails\Events\MailHardBounced;
use Vormkracht10\Mails\Events\MailUnsuppressed;
use Vormkracht10\Mails\Listeners\AttachMailLogUuid;
use Vormkracht10\Mails\Listeners\LogMailEvent;
use Vormkracht10\Mails\Listeners\LogSendingMail;
use Vormkracht10\Mails\Listeners\LogSentMail;
use Vormkracht10\Mails\Listeners\NotifyOnBounce;
use Vormkracht10\Mails\Listeners\StoreMailRelations;
use Vormkracht10\Mails\Listeners\UnsuppressEmailAddress;
use Vormkracht10\Mails\Managers\MailProviderManager;

class MailsServiceProvider extends PackageServiceProvider
Expand All @@ -35,6 +37,8 @@ public function registeringPackage(): void
$this->app['events']->listen(MailHardBounced::class, NotifyOnBounce::class);

$this->app['events']->listen(MessageSending::class, StoreMailRelations::class);

$this->app['events']->listen(MailUnsuppressed::class, UnsuppressEmailAddress::class);
}

public function bootingPackage(): void
Expand All @@ -53,6 +57,7 @@ public function configurePackage(Package $package): void
'2_create_mail_attachments_table',
'2_create_mail_events_table',
'2_create_mailables_table',
'3_add_unsuppressed_at_to_mail_events',
)
->hasRoutes('webhooks')
->hasCommands(
Expand Down
4 changes: 4 additions & 0 deletions src/Models/Mail.php
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ class Mail extends Model

protected $fillable = [
'uuid',
'mailer',
'stream_id',
'mail_class',
'subject',
'html',
Expand All @@ -75,6 +77,8 @@ class Mail extends Model
protected $casts = [
'id' => 'integer',
'uuid' => 'string',
'mailer' => 'string',
'stream_id' => 'string',
'subject' => 'string',
'from' => 'json',
'reply_to' => 'json',
Expand Down
2 changes: 2 additions & 0 deletions src/Models/MailEvent.php
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ class MailEvent extends Model
'tag',
'payload',
'occurred_at',
'unsuppressed_at',
];

protected $casts = [
Expand All @@ -57,6 +58,7 @@ class MailEvent extends Model
'created_at' => 'datetime',
'updated_at' => 'datetime',
'occurred_at' => 'datetime',
'unsuppressed_at' => 'datetime',
];

public function getTable()
Expand Down
3 changes: 3 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,5 +44,8 @@ public function getEnvironmentSetUp($app)

$migration = require __DIR__.'/../database/migrations/2_create_mailables_table.php.stub';
$migration->up();

$migration = require __DIR__.'/../database/migrations/3_add_unsuppressed_at_to_mail_events.php.stub';
$migration->up();
}
}

0 comments on commit 301f18b

Please sign in to comment.