diff --git a/app/Services/Billing/PlatformEmailClient.php b/app/Services/Billing/PlatformEmailClient.php index fd0fa52..64f671b 100644 --- a/app/Services/Billing/PlatformEmailClient.php +++ b/app/Services/Billing/PlatformEmailClient.php @@ -74,10 +74,12 @@ class PlatformEmailClient ->withHeaders(['Idempotency-Key' => $key]) ->acceptJson() ->timeout(30) + // from_name: pass the organizer/company display name. Do not default + // to EVENTS_SMTP_FROM_NAME ("Ladill Events") — attendee mail is from the customer. ->post($this->base().'/messages/send', array_filter([ 'user' => $ownerPublicId, 'channel' => 'suite', - 'from_name' => $fromName ?? config('smtp.from_name'), + 'from_name' => $fromName, 'to' => $to, 'subject' => $subject, 'html' => $html, diff --git a/app/Services/Events/EventEmailService.php b/app/Services/Events/EventEmailService.php index 02826f2..4b547c1 100644 --- a/app/Services/Events/EventEmailService.php +++ b/app/Services/Events/EventEmailService.php @@ -133,6 +133,8 @@ class EventEmailService $brandingSettings = AccountBranding::forOwnerRef($ownerPublicId); $viewData['logoUrl'] = AccountBranding::emailLogoUrl($brandingSettings); $viewData['companyName'] = AccountBranding::companyName($brandingSettings); + // From display: organizer name, else account/company branding — never "Ladill Events". + $fromName = trim((string) ($replyToName ?: $viewData['companyName'] ?? '')) ?: null; $html = View::make($view, $viewData)->render(); $text = strip_tags(str_replace(['
', '
', '
'], "\n", $html)); @@ -145,6 +147,7 @@ class EventEmailService $text, $replyToEmail, $replyToName, + $fromName, ); } } diff --git a/app/Services/Events/EventMailer.php b/app/Services/Events/EventMailer.php index 9d3acc5..465bb5a 100644 --- a/app/Services/Events/EventMailer.php +++ b/app/Services/Events/EventMailer.php @@ -5,6 +5,7 @@ namespace App\Services\Events; use App\Services\Billing\PlatformEmailClient; use App\Services\Messaging\CustomerEmailClient; use App\Services\Messaging\MessagingCredentialsService; +use App\Support\AccountBranding; /** * Attendee/speaker email: prefer platform suite messaging (zero-config mailbox), @@ -48,18 +49,20 @@ class EventMailer ?string $text = null, ?string $replyToEmail = null, ?string $replyToName = null, + ?string $fromName = null, ): bool { $this->lastError = null; + $displayName = $this->resolveFromName($ownerPublicId, $fromName, $replyToName); if ($this->platformEmail->isConfigured()) { - $sent = $this->platformEmail->send($ownerPublicId, $to, $subject, $html, $text); + $sent = $this->platformEmail->send($ownerPublicId, $to, $subject, $html, $text, $displayName); if ($sent) { return true; } // Suite unavailable (mailbox, allowance) — try Bird power-user path next. $suiteError = $this->platformEmail->lastError(); - if ($this->tryCustomerBird($ownerPublicId, $to, $subject, $html, $text)) { + if ($this->tryCustomerBird($ownerPublicId, $to, $subject, $html, $text, $displayName)) { return true; } @@ -68,7 +71,22 @@ class EventMailer return false; } - return $this->tryCustomerBird($ownerPublicId, $to, $subject, $html, $text); + return $this->tryCustomerBird($ownerPublicId, $to, $subject, $html, $text, $displayName); + } + + private function resolveFromName(string $ownerPublicId, ?string $fromName, ?string $replyToName): ?string + { + foreach ([$fromName, $replyToName] as $candidate) { + $name = trim((string) $candidate); + if ($name !== '') { + return $name; + } + } + + $settings = AccountBranding::forOwnerRef($ownerPublicId); + $company = trim(AccountBranding::companyName($settings)); + + return $company !== '' && strcasecmp($company, 'Company') !== 0 ? $company : null; } private function tryCustomerBird( @@ -77,6 +95,7 @@ class EventMailer string $subject, string $html, ?string $text, + ?string $fromName = null, ): bool { $credential = $this->credentials->forOwner($ownerPublicId); if (! $credential->hasValidBird()) { @@ -95,7 +114,7 @@ class EventMailer $sent = $this->customerEmail->send( $apiKey, (string) $credential->bird_from_email, - $credential->bird_from_name, + $credential->bird_from_name ?: $fromName, $to, $subject, $html, diff --git a/tests/Feature/EventsSuiteMessagingTest.php b/tests/Feature/EventsSuiteMessagingTest.php index c08a89f..44b3e3e 100644 --- a/tests/Feature/EventsSuiteMessagingTest.php +++ b/tests/Feature/EventsSuiteMessagingTest.php @@ -78,7 +78,10 @@ class EventsSuiteMessagingTest extends TestCase 'platform.test/api/smtp/messages/send' => Http::response(['success' => true]), ]); - $user = User::factory()->create(['public_id' => 'usr_mailer_suite']); + $user = User::factory()->create([ + 'public_id' => 'usr_mailer_suite', + 'name' => 'Acme Events Ltd', + ]); $ok = app(EventMailer::class)->send( $user->public_id, 'speaker@example.com', @@ -89,6 +92,13 @@ class EventsSuiteMessagingTest extends TestCase $this->assertTrue($ok); $this->assertTrue(app(EventMailer::class)->isConfiguredForOwner($user->public_id)); + Http::assertSent(function ($request) { + $data = $request->data(); + + return str_contains($request->url(), '/messages/send') + && ($data['channel'] ?? null) === 'suite' + && ($data['from_name'] ?? null) === 'Acme Events Ltd'; + }); } public function test_sms_service_uses_suite_when_platform_configured(): void