2026-05-27 07:29:29 +02:00
|
|
|
<?php
|
|
|
|
|
|
|
|
|
|
declare(strict_types=1);
|
|
|
|
|
|
|
|
|
|
namespace App\Models;
|
|
|
|
|
|
2026-06-17 13:50:41 +02:00
|
|
|
use App\Services\GoogleOAuthService;
|
2026-05-27 07:29:29 +02:00
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
|
|
|
use Illuminate\Database\Eloquent\Builder;
|
2026-06-17 13:50:41 +02:00
|
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
2026-05-27 07:29:29 +02:00
|
|
|
use Illuminate\Support\Facades\Crypt;
|
|
|
|
|
|
|
|
|
|
class SenderAccount extends Model
|
|
|
|
|
{
|
|
|
|
|
protected $table = 'sender_accounts';
|
|
|
|
|
|
|
|
|
|
protected $fillable = [
|
|
|
|
|
'email_address',
|
|
|
|
|
'email_name',
|
|
|
|
|
'smtp_host',
|
|
|
|
|
'smtp_port',
|
|
|
|
|
'smtp_encryption',
|
|
|
|
|
'smtp_username',
|
|
|
|
|
'smtp_password',
|
|
|
|
|
'reply_to',
|
|
|
|
|
'verify_email',
|
|
|
|
|
'note',
|
|
|
|
|
'is_active',
|
2026-06-17 13:50:41 +02:00
|
|
|
'auth_method',
|
|
|
|
|
'google_oauth_connection_id',
|
2026-05-27 07:29:29 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
protected $casts = [
|
|
|
|
|
'is_active' => 'boolean',
|
|
|
|
|
'smtp_port' => 'integer',
|
2026-06-17 13:50:41 +02:00
|
|
|
'google_oauth_connection_id' => 'integer',
|
2026-05-27 07:29:29 +02:00
|
|
|
];
|
|
|
|
|
|
|
|
|
|
public function scopeActive(Builder $query): Builder
|
|
|
|
|
{
|
|
|
|
|
return $query->where('is_active', true);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-17 13:50:41 +02:00
|
|
|
public function googleOAuthConnection(): BelongsTo
|
|
|
|
|
{
|
|
|
|
|
return $this->belongsTo(GoogleOAuthConnection::class);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected function resolveOAuthToken(): string
|
|
|
|
|
{
|
|
|
|
|
if (!$this->relationLoaded('googleOAuthConnection')) {
|
|
|
|
|
$this->load('googleOAuthConnection');
|
|
|
|
|
}
|
|
|
|
|
$connection = $this->googleOAuthConnection;
|
|
|
|
|
if (!$connection) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
try {
|
|
|
|
|
return app(GoogleOAuthService::class)->getAccessToken($connection);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-27 07:29:29 +02:00
|
|
|
public function getDecryptedPassword(): string
|
|
|
|
|
{
|
2026-06-17 13:50:41 +02:00
|
|
|
if ($this->auth_method === 'oauth') {
|
|
|
|
|
return $this->resolveOAuthToken();
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-27 07:29:29 +02:00
|
|
|
if (empty($this->smtp_password)) {
|
|
|
|
|
return '';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
return Crypt::decryptString($this->smtp_password);
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
return $this->smtp_password;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function sanitizeName(): string
|
|
|
|
|
{
|
|
|
|
|
$name = $this->email_name ?? '';
|
|
|
|
|
|
|
|
|
|
if (filter_var($name, FILTER_VALIDATE_EMAIL)) {
|
|
|
|
|
return 'Glastree';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$name = preg_replace('/[^\p{L}\p{N}\s]/u', '', $name);
|
|
|
|
|
$name = trim($name);
|
|
|
|
|
|
|
|
|
|
return empty($name) ? 'Glastree' : $name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function getReplyTo(): ?string
|
|
|
|
|
{
|
|
|
|
|
if ($this->reply_to) {
|
|
|
|
|
return $this->reply_to;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($this->verify_email) {
|
|
|
|
|
return $this->verify_email;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function buildDsn(): string
|
|
|
|
|
{
|
|
|
|
|
$password = $this->getDecryptedPassword();
|
|
|
|
|
$username = $this->smtp_username ?? $this->email_address;
|
|
|
|
|
$encryption = $this->smtp_encryption ?? 'tls';
|
|
|
|
|
$scheme = ($encryption === 'ssl') ? 'smtps' : 'smtp';
|
|
|
|
|
|
|
|
|
|
return sprintf(
|
|
|
|
|
'%s://%s:%s@%s:%d?encryption=%s',
|
|
|
|
|
$scheme,
|
|
|
|
|
rawurlencode($username),
|
|
|
|
|
rawurlencode($password),
|
|
|
|
|
$this->smtp_host ?? 'smtp.gmail.com',
|
|
|
|
|
$this->smtp_port ?? 587,
|
|
|
|
|
$encryption
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function buildSymfonyEmail(string $to, string $subject, string $body): \Symfony\Component\Mime\Email
|
|
|
|
|
{
|
|
|
|
|
$fromName = $this->sanitizeName();
|
|
|
|
|
$fromAddress = \Symfony\Component\Mime\Address::create($this->email_address, $fromName);
|
|
|
|
|
|
|
|
|
|
$email = (new \Symfony\Component\Mime\Email())
|
|
|
|
|
->from($fromAddress)
|
|
|
|
|
->to($to)
|
|
|
|
|
->subject($subject)
|
|
|
|
|
->text($body);
|
|
|
|
|
|
|
|
|
|
$replyTo = $this->getReplyTo();
|
|
|
|
|
if ($replyTo) {
|
|
|
|
|
$email->replyTo($replyTo);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return $email;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public function sendEmail(string $to, string $subject, string $body, array $attachmentPaths = []): void
|
|
|
|
|
{
|
|
|
|
|
$email = $this->buildSymfonyEmail($to, $subject, $body);
|
|
|
|
|
|
|
|
|
|
foreach ($attachmentPaths as $path) {
|
|
|
|
|
$email->attachFromPath($path);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-17 13:50:41 +02:00
|
|
|
if ($this->auth_method === 'oauth') {
|
|
|
|
|
$mailer = $this->buildOAuthMailer();
|
|
|
|
|
} else {
|
|
|
|
|
$transport = \Symfony\Component\Mailer\Transport::fromDsn($this->buildDsn());
|
|
|
|
|
$mailer = new \Symfony\Component\Mailer\Mailer($transport);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-27 07:29:29 +02:00
|
|
|
$mailer->send($email);
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-17 13:50:41 +02:00
|
|
|
protected function buildOAuthMailer(): \Symfony\Component\Mailer\Mailer
|
|
|
|
|
{
|
|
|
|
|
$token = $this->resolveOAuthToken();
|
|
|
|
|
$username = $this->smtp_username ?? $this->email_address;
|
|
|
|
|
$host = $this->smtp_host ?? 'smtp.gmail.com';
|
|
|
|
|
$port = $this->smtp_port ?? 587;
|
|
|
|
|
|
|
|
|
|
$transport = new \Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport($host, $port, true);
|
|
|
|
|
$transport->setUsername($username);
|
|
|
|
|
$transport->setPassword($token);
|
|
|
|
|
$transport->setAuthenticators([
|
|
|
|
|
new \Symfony\Component\Mailer\Transport\Smtp\Auth\XOAuth2Authenticator(),
|
|
|
|
|
]);
|
|
|
|
|
|
|
|
|
|
return new \Symfony\Component\Mailer\Mailer($transport);
|
|
|
|
|
}
|
|
|
|
|
|
2026-05-27 07:29:29 +02:00
|
|
|
public function sendReport(string $subject, string $body): bool
|
|
|
|
|
{
|
|
|
|
|
if (empty($this->verify_email)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
$this->sendEmail($this->verify_email, $subject, $body);
|
|
|
|
|
return true;
|
|
|
|
|
} catch (\Exception $e) {
|
|
|
|
|
\Illuminate\Support\Facades\Log::error('Sender report email failed', [
|
|
|
|
|
'sender' => $this->email_address,
|
|
|
|
|
'error' => $e->getMessage(),
|
|
|
|
|
]);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|