Send Events mail from platform SMTP like Invoice, not owner Bird domain.
Deploy Ladill Events / deploy (push) Successful in 31s

Use EventMailer with MAIL_FROM and organiser Reply-To instead of the Bird API, which rewrote the From address onto the account's verified domain (e.g. climp.me). Redesign the speaker invitation to use the shared Events email layout.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-03 17:09:05 +00:00
co-authored by Cursor
parent 1db499ba2f
commit 0c5a1ddb23
8 changed files with 233 additions and 31 deletions
+43 -7
View File
@@ -2,16 +2,15 @@
namespace App\Services\Events;
use App\Services\Billing\PlatformEmailClient;
use Illuminate\Support\Facades\View;
class EventEmailService
{
public function __construct(private readonly PlatformEmailClient $platform) {}
public function __construct(private readonly EventMailer $mailer) {}
public function lastError(): ?string
{
return $this->platform->lastError();
return $this->mailer->lastError();
}
public function sendProgrammeShare(
@@ -20,6 +19,8 @@ class EventEmailService
string $eventName,
string $programmeUrl,
?string $attendeeName = null,
?string $organizerEmail = null,
?string $organizerName = null,
): bool {
return $this->send(
$ownerPublicId,
@@ -27,6 +28,9 @@ class EventEmailService
'Programme for '.$eventName,
'mail.notifications.event-programme',
compact('eventName', 'programmeUrl', 'attendeeName'),
$eventName,
$organizerEmail,
$organizerName,
);
}
@@ -36,6 +40,8 @@ class EventEmailService
string $eventName,
string $joinUrl,
?string $attendeeName = null,
?string $organizerEmail = null,
?string $organizerName = null,
): bool {
return $this->send(
$ownerPublicId,
@@ -43,6 +49,9 @@ class EventEmailService
'Join '.$eventName,
'mail.notifications.event-join',
compact('eventName', 'joinUrl', 'attendeeName'),
$eventName,
$organizerEmail,
$organizerName,
);
}
@@ -53,6 +62,8 @@ class EventEmailService
string $joinUrl,
string $programmeUrl,
?string $attendeeName = null,
?string $organizerEmail = null,
?string $organizerName = null,
): bool {
return $this->send(
$ownerPublicId,
@@ -60,6 +71,9 @@ class EventEmailService
$eventName.' — programme & join link',
'mail.notifications.event-join-programme',
compact('eventName', 'joinUrl', 'programmeUrl', 'attendeeName'),
$eventName,
$organizerEmail,
$organizerName,
);
}
@@ -70,6 +84,8 @@ class EventEmailService
string $badgeCode,
?string $joinUrl = null,
?string $attendeeName = null,
?string $organizerEmail = null,
?string $organizerName = null,
): bool {
return $this->send(
$ownerPublicId,
@@ -77,6 +93,9 @@ class EventEmailService
'Registration confirmed — '.$eventName,
'mail.notifications.event-registration-confirmed',
compact('eventName', 'badgeCode', 'joinUrl', 'attendeeName'),
$eventName,
$organizerEmail,
$organizerName,
);
}
@@ -86,6 +105,8 @@ class EventEmailService
string $eventName,
string $portalUrl,
?string $speakerName = null,
?string $organizerEmail = null,
?string $organizerName = null,
): bool {
return $this->send(
$ownerPublicId,
@@ -97,20 +118,35 @@ class EventEmailService
'portalUrl' => $portalUrl,
'speakerName' => $speakerName,
],
$eventName,
$organizerEmail,
$organizerName,
);
}
/** @param array<string, mixed> $viewData */
private function send(string $ownerPublicId, string $to, string $subject, string $view, array $viewData): bool
{
private function send(
string $ownerPublicId,
string $to,
string $subject,
string $view,
array $viewData,
?string $fromDisplayName = null,
?string $replyToEmail = null,
?string $replyToName = null,
): bool {
$html = View::make($view, $viewData)->render();
$text = strip_tags(str_replace(['<br>', '<br/>', '<br />'], "\n", $html));
return $this->platform->send(
return $this->mailer->send(
$ownerPublicId,
$to,
$subject,
$html,
strip_tags(str_replace(['<br>', '<br/>', '<br />'], "\n", $html)),
$text,
$fromDisplayName,
$replyToEmail,
$replyToName,
);
}
}