fix: split drip and default email senders (#263)
## Summary - route drip mailables through `Álvaro and Víctor <hi@whisper.money>` and send the rest from `Whisper Money <no-reply@whisper.money>` - remove legacy per-mailable `Victor` sender overrides so non-drip mail falls back to the default sender consistently - add focused sender coverage for drip, non-drip, and verification mail paths ## Testing - `php artisan test --compact tests/Feature/MailSenderTest.php tests/Feature/Jobs/Drip/SendWelcomeEmailJobTest.php`
This commit is contained in:
parent
3990472249
commit
ce5692cb30
|
|
@ -51,8 +51,10 @@ MAIL_HOST=127.0.0.1
|
|||
MAIL_PORT=1025
|
||||
MAIL_USERNAME=null
|
||||
MAIL_PASSWORD=null
|
||||
MAIL_FROM_ADDRESS="hi@whisper.money"
|
||||
MAIL_FROM_ADDRESS="no-reply@whisper.money"
|
||||
MAIL_FROM_NAME="Whisper Money"
|
||||
MAIL_DRIP_FROM_ADDRESS="hi@whisper.money"
|
||||
MAIL_DRIP_FROM_NAME="Álvaro and Víctor"
|
||||
ADMIN_EMAIL=
|
||||
|
||||
# Resend Email Service (set MAIL_MAILER=resend to use in production)
|
||||
|
|
|
|||
|
|
@ -43,8 +43,10 @@ REDIS_PORT=6379
|
|||
# Email - Resend (Recommended for production)
|
||||
MAIL_MAILER=resend
|
||||
RESEND_API_KEY=your-resend-api-key
|
||||
MAIL_FROM_ADDRESS=hi@your-domain.com
|
||||
MAIL_FROM_ADDRESS=no-reply@your-domain.com
|
||||
MAIL_FROM_NAME="Whisper Money"
|
||||
MAIL_DRIP_FROM_ADDRESS=hi@your-domain.com
|
||||
MAIL_DRIP_FROM_NAME="Álvaro and Víctor"
|
||||
|
||||
# Stripe (Optional - for subscriptions)
|
||||
STRIPE_KEY=
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ class BankTransactionsSyncedEmail extends Mailable implements ShouldQueue
|
|||
{
|
||||
return new Envelope(
|
||||
subject: __(':count new transactions synced on Whisper Money', ['count' => $this->totalTransactions]),
|
||||
)->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ class BankingConnectionAuthFailedEmail extends Mailable implements ShouldQueue
|
|||
subject: __('Action required: :provider connection needs attention', [
|
||||
'provider' => $this->bankingConnection->aspsp_name,
|
||||
]),
|
||||
)->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ class BrokenBankLogosReportEmail extends Mailable
|
|||
|
||||
return new Envelope(
|
||||
subject: trans_choice('Weekly bank logo audit: :count broken logo|Weekly bank logo audit: :count broken logos', $updatedCount, ['count' => $updatedCount]),
|
||||
)->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Models\User;
|
|||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -37,8 +38,12 @@ class FeedbackEmail extends Mailable implements ShouldQueue
|
|||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
from: new Address(
|
||||
config('mail.drip_from.address', 'hi@whisper.money'),
|
||||
config('mail.drip_from.name', 'Álvaro and Víctor'),
|
||||
),
|
||||
subject: __("How's Your Experience So Far?"),
|
||||
)->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Models\User;
|
|||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -37,8 +38,12 @@ class ImportHelpEmail extends Mailable implements ShouldQueue
|
|||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
from: new Address(
|
||||
config('mail.drip_from.address', 'hi@whisper.money'),
|
||||
config('mail.drip_from.name', 'Álvaro and Víctor'),
|
||||
),
|
||||
subject: __("Let's Import Your Transactions"),
|
||||
)->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Models\User;
|
|||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -37,8 +38,12 @@ class OnboardingReminderEmail extends Mailable implements ShouldQueue
|
|||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
from: new Address(
|
||||
config('mail.drip_from.address', 'hi@whisper.money'),
|
||||
config('mail.drip_from.name', 'Álvaro and Víctor'),
|
||||
),
|
||||
subject: __('Need Help Getting Started?'),
|
||||
)->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Models\User;
|
|||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -36,9 +37,13 @@ class PromoCodeEmail extends Mailable implements ShouldQueue
|
|||
|
||||
public function envelope(): Envelope
|
||||
{
|
||||
return (new Envelope(
|
||||
return new Envelope(
|
||||
from: new Address(
|
||||
config('mail.drip_from.address', 'hi@whisper.money'),
|
||||
config('mail.drip_from.name', 'Álvaro and Víctor'),
|
||||
),
|
||||
subject: __('Your Founder Discount - 80% Off First Period')
|
||||
))->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Models\User;
|
|||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -37,8 +38,12 @@ class SubscriptionCancelledEmail extends Mailable implements ShouldQueue
|
|||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
from: new Address(
|
||||
config('mail.drip_from.address', 'hi@whisper.money'),
|
||||
config('mail.drip_from.name', 'Álvaro and Víctor'),
|
||||
),
|
||||
subject: __("We're sorry to see you go"),
|
||||
)->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ use App\Models\User;
|
|||
use Illuminate\Bus\Queueable;
|
||||
use Illuminate\Contracts\Queue\ShouldQueue;
|
||||
use Illuminate\Mail\Mailable;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailables\Content;
|
||||
use Illuminate\Mail\Mailables\Envelope;
|
||||
use Illuminate\Queue\Middleware\RateLimited;
|
||||
|
|
@ -37,8 +38,12 @@ class WelcomeEmail extends Mailable implements ShouldQueue
|
|||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
from: new Address(
|
||||
config('mail.drip_from.address', 'hi@whisper.money'),
|
||||
config('mail.drip_from.name', 'Álvaro and Víctor'),
|
||||
),
|
||||
subject: __('Welcome to Whisper Money - Your Privacy-First Finance App'),
|
||||
)->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ class UpdateEmail extends Mailable implements ShouldQueue
|
|||
{
|
||||
return new Envelope(
|
||||
subject: $this->emailSubject,
|
||||
)->from(config('mail.from.address', 'hello@example.com'), 'Victor');
|
||||
);
|
||||
}
|
||||
|
||||
public function content(): Content
|
||||
|
|
|
|||
|
|
@ -45,7 +45,10 @@ class WaitlistOvertaken extends Mailable implements ShouldQueue
|
|||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
from: new Address('victor@whisper.money', 'Victor & Alvaro from Whisper Money'),
|
||||
from: new Address(
|
||||
config('mail.from.address', 'no-reply@whisper.money'),
|
||||
config('mail.from.name', 'Whisper Money'),
|
||||
),
|
||||
subject: __('Someone just overtook you in the Whisper Money queue!'),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,7 +45,10 @@ class WaitlistReferralNotification extends Mailable implements ShouldQueue
|
|||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
from: new Address('victor@whisper.money', 'Victor & Alvaro from Whisper Money'),
|
||||
from: new Address(
|
||||
config('mail.from.address', 'no-reply@whisper.money'),
|
||||
config('mail.from.name', 'Whisper Money'),
|
||||
),
|
||||
subject: __('Someone just joined Whisper Money with your link!'),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,7 +46,10 @@ class WaitlistWelcome extends Mailable implements ShouldQueue
|
|||
public function envelope(): Envelope
|
||||
{
|
||||
return new Envelope(
|
||||
from: new Address('victor@whisper.money', 'Victor from Whisper Money'),
|
||||
from: new Address(
|
||||
config('mail.from.address', 'no-reply@whisper.money'),
|
||||
config('mail.from.name', 'Whisper Money'),
|
||||
),
|
||||
subject: __("You're on the Whisper Money waiting list!"),
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ class VerifyEmailNotification extends VerifyEmail
|
|||
$verificationUrl = $this->verificationUrl($notifiable);
|
||||
|
||||
return (new MailMessage)
|
||||
->from(config('mail.from.address', 'hello@example.com'), 'Victor')
|
||||
->subject(__('Verify Your Email - Whisper Money'))
|
||||
->markdown('mail.verify-email', [
|
||||
'userName' => $notifiable->name,
|
||||
|
|
|
|||
|
|
@ -139,8 +139,13 @@ return [
|
|||
*/
|
||||
|
||||
'from' => [
|
||||
'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'),
|
||||
'name' => env('MAIL_FROM_NAME', 'Example'),
|
||||
'address' => env('MAIL_FROM_ADDRESS', 'no-reply@whisper.money'),
|
||||
'name' => env('MAIL_FROM_NAME', 'Whisper Money'),
|
||||
],
|
||||
|
||||
'drip_from' => [
|
||||
'address' => env('MAIL_DRIP_FROM_ADDRESS', 'hi@whisper.money'),
|
||||
'name' => env('MAIL_DRIP_FROM_NAME', 'Álvaro and Víctor'),
|
||||
],
|
||||
|
||||
];
|
||||
|
|
|
|||
|
|
@ -5,64 +5,76 @@
|
|||
# port: 80
|
||||
|
||||
services:
|
||||
whisper-money:
|
||||
image: ghcr.io/whisper-money/whisper-money:latest
|
||||
environment:
|
||||
- SERVICE_FQDN_WHISPERMONEY_80
|
||||
- APP_NAME=Whisper Money
|
||||
- APP_ENV=production
|
||||
- APP_DEBUG=false
|
||||
- APP_URL=${SERVICE_FQDN_WHISPERMONEY_80}
|
||||
# APP_KEY is auto-generated on first startup if not provided
|
||||
- DB_CONNECTION=mysql
|
||||
- DB_HOST=mysql
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=${MYSQL_DATABASE:-whisper_money}
|
||||
- DB_USERNAME=${SERVICE_USER_MYSQL}
|
||||
- DB_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
||||
- CACHE_STORE=redis
|
||||
- SESSION_DRIVER=redis
|
||||
- QUEUE_CONNECTION=database
|
||||
- REDIS_HOST=127.0.0.1
|
||||
- HIDE_AUTH_BUTTONS=${HIDE_AUTH_BUTTONS:-false}
|
||||
- MAIL_MAILER=${MAIL_MAILER:-log}
|
||||
- MAIL_HOST=${MAIL_HOST:-}
|
||||
- MAIL_PORT=${MAIL_PORT:-587}
|
||||
- MAIL_USERNAME=${MAIL_USERNAME:-}
|
||||
- MAIL_PASSWORD=${MAIL_PASSWORD:-}
|
||||
- MAIL_FROM_ADDRESS=${MAIL_FROM_ADDRESS:-hi@whisper.money}
|
||||
- MAIL_FROM_NAME=${MAIL_FROM_NAME:-Whisper Money}
|
||||
- RESEND_API_KEY=${RESEND_API_KEY:-}
|
||||
- STRIPE_KEY=${STRIPE_KEY:-}
|
||||
- STRIPE_SECRET=${STRIPE_SECRET:-}
|
||||
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET:-}
|
||||
- SUBSCRIPTIONS_ENABLED=${SUBSCRIPTIONS_ENABLED:-false}
|
||||
volumes:
|
||||
- whisper-money-storage:/app/storage
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost/up"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
whisper-money:
|
||||
image: ghcr.io/whisper-money/whisper-money:latest
|
||||
environment:
|
||||
- SERVICE_FQDN_WHISPERMONEY_80
|
||||
- APP_NAME=Whisper Money
|
||||
- APP_ENV=production
|
||||
- APP_DEBUG=false
|
||||
- APP_URL=${SERVICE_FQDN_WHISPERMONEY_80}
|
||||
# APP_KEY is auto-generated on first startup if not provided
|
||||
- DB_CONNECTION=mysql
|
||||
- DB_HOST=mysql
|
||||
- DB_PORT=3306
|
||||
- DB_DATABASE=${MYSQL_DATABASE:-whisper_money}
|
||||
- DB_USERNAME=${SERVICE_USER_MYSQL}
|
||||
- DB_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
||||
- CACHE_STORE=redis
|
||||
- SESSION_DRIVER=redis
|
||||
- QUEUE_CONNECTION=database
|
||||
- REDIS_HOST=127.0.0.1
|
||||
- HIDE_AUTH_BUTTONS=${HIDE_AUTH_BUTTONS:-false}
|
||||
- MAIL_MAILER=${MAIL_MAILER:-log}
|
||||
- MAIL_HOST=${MAIL_HOST:-}
|
||||
- MAIL_PORT=${MAIL_PORT:-587}
|
||||
- MAIL_USERNAME=${MAIL_USERNAME:-}
|
||||
- MAIL_PASSWORD=${MAIL_PASSWORD:-}
|
||||
- MAIL_FROM_ADDRESS=${MAIL_FROM_ADDRESS:-no-reply@whisper.money}
|
||||
- MAIL_FROM_NAME=${MAIL_FROM_NAME:-Whisper Money}
|
||||
- MAIL_DRIP_FROM_ADDRESS=${MAIL_DRIP_FROM_ADDRESS:-hi@whisper.money}
|
||||
- MAIL_DRIP_FROM_NAME=${MAIL_DRIP_FROM_NAME:-Álvaro and Víctor}
|
||||
- RESEND_API_KEY=${RESEND_API_KEY:-}
|
||||
- STRIPE_KEY=${STRIPE_KEY:-}
|
||||
- STRIPE_SECRET=${STRIPE_SECRET:-}
|
||||
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET:-}
|
||||
- SUBSCRIPTIONS_ENABLED=${SUBSCRIPTIONS_ENABLED:-false}
|
||||
volumes:
|
||||
- whisper-money-storage:/app/storage
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
healthcheck:
|
||||
test: ['CMD', 'curl', '-f', 'http://localhost/up']
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT}
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE:-whisper_money}
|
||||
- MYSQL_USER=${SERVICE_USER_MYSQL}
|
||||
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
||||
volumes:
|
||||
- whisper-money-mysql:/var/lib/mysql
|
||||
healthcheck:
|
||||
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-p${SERVICE_PASSWORD_MYSQLROOT}"]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
mysql:
|
||||
image: mysql:8.0
|
||||
environment:
|
||||
- MYSQL_ROOT_PASSWORD=${SERVICE_PASSWORD_MYSQLROOT}
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE:-whisper_money}
|
||||
- MYSQL_USER=${SERVICE_USER_MYSQL}
|
||||
- MYSQL_PASSWORD=${SERVICE_PASSWORD_MYSQL}
|
||||
volumes:
|
||||
- whisper-money-mysql:/var/lib/mysql
|
||||
healthcheck:
|
||||
test:
|
||||
[
|
||||
'CMD',
|
||||
'mysqladmin',
|
||||
'ping',
|
||||
'-h',
|
||||
'localhost',
|
||||
'-u',
|
||||
'root',
|
||||
'-p${SERVICE_PASSWORD_MYSQLROOT}',
|
||||
]
|
||||
interval: 5s
|
||||
timeout: 5s
|
||||
retries: 10
|
||||
|
||||
volumes:
|
||||
whisper-money-storage:
|
||||
whisper-money-mysql:
|
||||
whisper-money-storage:
|
||||
whisper-money-mysql:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,8 @@ test('welcome email is sent and logged', function () {
|
|||
SendWelcomeEmailJob::dispatchSync($user);
|
||||
|
||||
Mail::assertQueued(WelcomeEmail::class, function ($mail) use ($user) {
|
||||
return $mail->hasTo($user->email);
|
||||
return $mail->hasTo($user->email)
|
||||
&& $mail->hasFrom('hi@whisper.money', 'Álvaro and Víctor');
|
||||
});
|
||||
|
||||
$this->assertDatabaseHas('user_mail_logs', [
|
||||
|
|
|
|||
|
|
@ -0,0 +1,141 @@
|
|||
<?php
|
||||
|
||||
use App\Mail\BankingConnectionAuthFailedEmail;
|
||||
use App\Mail\BankTransactionsSyncedEmail;
|
||||
use App\Mail\BrokenBankLogosReportEmail;
|
||||
use App\Mail\Drip\FeedbackEmail;
|
||||
use App\Mail\Drip\ImportHelpEmail;
|
||||
use App\Mail\Drip\OnboardingReminderEmail;
|
||||
use App\Mail\Drip\PromoCodeEmail;
|
||||
use App\Mail\Drip\SubscriptionCancelledEmail;
|
||||
use App\Mail\Drip\WelcomeEmail;
|
||||
use App\Mail\UpdateEmail;
|
||||
use App\Mail\WaitlistOvertaken;
|
||||
use App\Mail\WaitlistReferralNotification;
|
||||
use App\Mail\WaitlistWelcome;
|
||||
use App\Models\BankingConnection;
|
||||
use App\Models\User;
|
||||
use App\Models\UserLead;
|
||||
use App\Notifications\VerifyEmailNotification;
|
||||
use Illuminate\Mail\Mailables\Address;
|
||||
use Illuminate\Mail\Mailer;
|
||||
use Illuminate\Mail\Transport\ArrayTransport;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
|
||||
beforeEach(function () {
|
||||
config([
|
||||
'mail.default' => 'array',
|
||||
'mail.from.address' => 'no-reply@whisper.money',
|
||||
'mail.from.name' => 'Whisper Money',
|
||||
'mail.drip_from.address' => 'hi@whisper.money',
|
||||
'mail.drip_from.name' => 'Álvaro and Víctor',
|
||||
]);
|
||||
|
||||
$viewPath = resource_path('views/mail/updates');
|
||||
|
||||
if (! File::exists($viewPath)) {
|
||||
File::makeDirectory($viewPath, 0755, true);
|
||||
}
|
||||
|
||||
File::put(resource_path('views/mail/updates/test-update.blade.php'), <<<'BLADE'
|
||||
<x-mail::message>
|
||||
# Test Update
|
||||
|
||||
Hello {{ $user->name }},
|
||||
|
||||
Test update.
|
||||
</x-mail::message>
|
||||
BLADE);
|
||||
});
|
||||
|
||||
afterEach(function () {
|
||||
$testViewPath = resource_path('views/mail/updates/test-update.blade.php');
|
||||
|
||||
if (File::exists($testViewPath)) {
|
||||
File::delete($testViewPath);
|
||||
}
|
||||
});
|
||||
|
||||
function lastSentMailMessage(): object
|
||||
{
|
||||
/** @var Mailer $mailer */
|
||||
$mailer = Mail::mailer('array');
|
||||
/** @var ArrayTransport $transport */
|
||||
$transport = $mailer->getSymfonyTransport();
|
||||
|
||||
return $transport->messages()->last();
|
||||
}
|
||||
|
||||
function sendWithArrayMailer($mailable): void
|
||||
{
|
||||
/** @var Mailer $mailer */
|
||||
$mailer = Mail::mailer('array');
|
||||
/** @var ArrayTransport $transport */
|
||||
$transport = $mailer->getSymfonyTransport();
|
||||
$transport->flush();
|
||||
|
||||
$mailer->to('recipient@example.com')->sendNow($mailable);
|
||||
}
|
||||
|
||||
test('drip mailables use the drip sender', function (string $mailableClass) {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$mailable = match ($mailableClass) {
|
||||
WelcomeEmail::class => new WelcomeEmail($user),
|
||||
FeedbackEmail::class => new FeedbackEmail($user),
|
||||
ImportHelpEmail::class => new ImportHelpEmail($user),
|
||||
OnboardingReminderEmail::class => new OnboardingReminderEmail($user),
|
||||
PromoCodeEmail::class => new PromoCodeEmail($user),
|
||||
SubscriptionCancelledEmail::class => new SubscriptionCancelledEmail($user),
|
||||
};
|
||||
|
||||
expect($mailable->envelope()->from)->toEqual(new Address('hi@whisper.money', 'Álvaro and Víctor'));
|
||||
})->with([
|
||||
WelcomeEmail::class,
|
||||
FeedbackEmail::class,
|
||||
ImportHelpEmail::class,
|
||||
OnboardingReminderEmail::class,
|
||||
PromoCodeEmail::class,
|
||||
SubscriptionCancelledEmail::class,
|
||||
]);
|
||||
|
||||
test('default sender is used for active non-drip mailables', function (string $mailableClass) {
|
||||
$user = User::factory()->create();
|
||||
|
||||
$mailable = match ($mailableClass) {
|
||||
UpdateEmail::class => new UpdateEmail($user, 'test-update'),
|
||||
BankTransactionsSyncedEmail::class => new BankTransactionsSyncedEmail($user, 3, ['Test Bank' => 3]),
|
||||
BankingConnectionAuthFailedEmail::class => new BankingConnectionAuthFailedEmail($user, BankingConnection::factory()->for($user)->create(['aspsp_name' => 'Test Bank'])),
|
||||
BrokenBankLogosReportEmail::class => new BrokenBankLogosReportEmail([['id' => 'bank-1', 'name' => 'Test Bank', 'previous_logo' => 'https://example.com/logo.png']]),
|
||||
WaitlistWelcome::class => new WaitlistWelcome(UserLead::factory()->create()),
|
||||
WaitlistReferralNotification::class => new WaitlistReferralNotification(UserLead::factory()->create()),
|
||||
WaitlistOvertaken::class => new WaitlistOvertaken(UserLead::factory()->create()),
|
||||
};
|
||||
|
||||
sendWithArrayMailer($mailable);
|
||||
|
||||
$from = lastSentMailMessage()->getOriginalMessage()->getFrom()[0];
|
||||
|
||||
expect($from->getAddress())->toBe('no-reply@whisper.money')
|
||||
->and($from->getName())->toBe('Whisper Money');
|
||||
})->with([
|
||||
UpdateEmail::class,
|
||||
BankTransactionsSyncedEmail::class,
|
||||
BankingConnectionAuthFailedEmail::class,
|
||||
BrokenBankLogosReportEmail::class,
|
||||
WaitlistWelcome::class,
|
||||
WaitlistReferralNotification::class,
|
||||
WaitlistOvertaken::class,
|
||||
]);
|
||||
|
||||
test('verification notification uses the default sender', function () {
|
||||
$user = User::factory()->unverified()->create();
|
||||
|
||||
$user->notify(new VerifyEmailNotification);
|
||||
|
||||
$from = lastSentMailMessage()->getOriginalMessage()->getFrom()[0];
|
||||
|
||||
expect($from->getAddress())->toBe('no-reply@whisper.money')
|
||||
->and($from->getName())->toBe('Whisper Money');
|
||||
});
|
||||
Loading…
Reference in New Issue