HEX
Server: LiteSpeed
System: Linux s1049.use1.mysecurecloudhost.com 4.18.0-477.27.2.lve.el8.x86_64 #1 SMP Wed Oct 11 12:32:56 UTC 2023 x86_64
User: xedaptot (3356)
PHP: 8.3.31
Disabled: NONE
Upload Files
File: /home/xedaptot/hi.naniguide.com/app/Services/DeliveryServerService.php
<?php

namespace App\Services;

use App\Models\Customer;
use App\Models\DeliveryServer;
use App\Models\DeliveryServerLog;
use App\Models\Setting;
use App\Mail\DeliveryServerVerificationMailable;
use App\Services\ZeptoMailApiService;
use App\Services\EmailitApiService;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Config;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Schema;
use Illuminate\Support\Collection;

class DeliveryServerService
{
    protected function selectableDeliveryServersQueryForCustomer(Customer $customer, bool $mustAddDelivery = false, bool $canUseSystem = false): Builder
    {
        $workspaceId = session('active_workspace_id');
        $allocatedSystemServerIds = collect();

        if (Schema::hasTable('customer_delivery_server')) {
            $allocatedSystemServerIds = $allocatedSystemServerIds->merge(
                $customer->allocatedDeliveryServers()
                ->whereNull('delivery_servers.customer_id')
                ->pluck('delivery_servers.id')
                ->map(fn ($id) => (int) $id)
                ->filter(fn ($id) => $id > 0)
            );
        }

        $groupIds = collect();
        if (Schema::hasTable('customer_customer_group') || method_exists($customer, 'customerGroups')) {
            $groupIds = $customer->customerGroups()->pluck('customer_groups.id')
                ->map(fn ($id) => (int) $id)
                ->filter(fn ($id) => $id > 0)
                ->unique()
                ->values();
        }

        if ($groupIds->isNotEmpty() && Schema::hasTable('customer_group_delivery_server')) {
            $groupAllocatedIds = DB::table('customer_group_delivery_server')
                ->join('delivery_servers', 'delivery_servers.id', '=', 'customer_group_delivery_server.delivery_server_id')
                ->whereIn('customer_group_id', $groupIds->all())
                ->whereNull('delivery_servers.customer_id')
                ->whereNull('delivery_servers.deleted_at')
                ->pluck('delivery_server_id')
                ->map(fn ($id) => (int) $id)
                ->filter(fn ($id) => $id > 0)
                ->unique()
                ->values();

            if ($groupAllocatedIds->isNotEmpty()) {
                $allocatedSystemServerIds = $allocatedSystemServerIds->merge($groupAllocatedIds);
            }
        }

        $allocatedSystemServerIds = $allocatedSystemServerIds
            ->unique()
            ->values();

        if ($workspaceId) {
            return DeliveryServer::query()
                ->where('status', 'active')
                ->when($allocatedSystemServerIds->isNotEmpty(), function ($q) use ($workspaceId, $allocatedSystemServerIds, $canUseSystem) {
                    $q->where(function ($sub) use ($workspaceId, $allocatedSystemServerIds, $canUseSystem) {
                        $sub->where('workspace_id', $workspaceId);
                        if ($canUseSystem) {
                            $sub->orWhereIn('id', $allocatedSystemServerIds->all())
                                ->orWhereNull('workspace_id');
                        }
                    });
                }, function ($q) use ($workspaceId, $canUseSystem) {
                    $q->where(function ($sub) use ($workspaceId, $canUseSystem) {
                        $sub->where('workspace_id', $workspaceId);
                        if ($canUseSystem) {
                            $sub->orWhereNull('workspace_id');
                        }
                    });
                });
        }

        if ($allocatedSystemServerIds->isNotEmpty()) {
            return DeliveryServer::query()
                ->where('status', 'active')
                ->where(function ($q) use ($customer, $allocatedSystemServerIds) {
                    $q->where('customer_id', $customer->id)
                        ->orWhereIn('id', $allocatedSystemServerIds->all());
                });
        }

        return DeliveryServer::query()
            ->where('status', 'active')
            ->where('use_for', true)
            ->when($mustAddDelivery, function ($q) use ($customer) {
                $q->where('customer_id', $customer->id);
            }, function ($q) use ($customer, $canUseSystem) {
                $q->where(function ($sub) use ($customer, $canUseSystem) {
                    $sub->where('customer_id', $customer->id);
                    if ($canUseSystem) {
                        $sub->orWhereNull('customer_id');
                    }
                });
            });
    }

    public function querySelectableDeliveryServersForCustomer(Customer $customer, bool $mustAddDelivery = false, bool $canUseSystem = false): Builder
    {
        return $this->selectableDeliveryServersQueryForCustomer($customer, $mustAddDelivery, $canUseSystem);
    }

    public function getSelectableDeliveryServersForCustomer(Customer $customer, bool $mustAddDelivery = false, bool $canUseSystem = false): Collection
    {
        return $this->selectableDeliveryServersQueryForCustomer($customer, $mustAddDelivery, $canUseSystem)
            ->orderBy('name')
            ->get();
    }

    public function getSelectableDeliveryServerIdsForCustomer(Customer $customer, bool $mustAddDelivery = false, bool $canUseSystem = false): array
    {
        return $this->selectableDeliveryServersQueryForCustomer($customer, $mustAddDelivery, $canUseSystem)
            ->pluck('id')
            ->map(fn ($id) => (int) $id)
            ->filter(fn ($id) => $id > 0)
            ->values()
            ->all();
    }

    public function queryAdminEmailSettingDeliveryServers(): Builder
    {
        return DeliveryServer::query()
            ->where('status', 'active')
            ->whereNull('customer_id')
            ->orderByDesc('is_primary')
            ->orderBy('name');
    }

    public function resolveAdminEmailSettingDeliveryServer(mixed $selected): ?DeliveryServer
    {
        if ($selected instanceof DeliveryServer) {
            return $selected->exists ? $selected : null;
        }

        if ($selected === null) {
            return null;
        }

        if (is_string($selected)) {
            $selected = trim($selected);
        }

        if ($selected === '' || $selected === 'auto' || $selected === 'inherit' || $selected === 'system') {
            return null;
        }

        if (is_int($selected)) {
            $serverId = $selected;
        } elseif (is_string($selected) && ctype_digit($selected)) {
            $serverId = (int) $selected;
        } else {
            return null;
        }

        if ($serverId <= 0) {
            return null;
        }

        return $this->queryAdminEmailSettingDeliveryServers()
            ->whereKey($serverId)
            ->first();
    }

    public function resolveDeliveryServerForCustomer(Customer $customer, ?int $requestedServerId, bool $mustAddDelivery = false, bool $canUseSystem = false): ?DeliveryServer
    {
        if ($requestedServerId) {
            $requested = $this->selectableDeliveryServersQueryForCustomer($customer, $mustAddDelivery, $canUseSystem)
                ->with('bounceServer')
                ->whereKey($requestedServerId)
                ->first();
            if ($requested) {
                return $requested;
            }
        }

        return $this->selectableDeliveryServersQueryForCustomer($customer, $mustAddDelivery, $canUseSystem)
            ->with('bounceServer')
            ->orderBy('id')
            ->first();
    }

    protected function ensureProviderWebhooksStored(DeliveryServer $deliveryServer): void
    {
        try {
            $type = $deliveryServer->type;
            if (!in_array($type, ['mailgun', 'sendgrid', 'amazon-ses', 'resend'], true)) {
                return;
            }

            $base = rtrim((string) config('app.url'), '/');
            $urls = match ($type) {
                'mailgun' => [
                    'bounce' => $base . '/webhooks/mailgun/bounce',
                    'open' => $base . '/webhooks/mailgun/open',
                    'click' => $base . '/webhooks/mailgun/click',
                ],
                'sendgrid' => [
                    'bounce' => $base . '/webhooks/sendgrid/bounce',
                    'open' => $base . '/webhooks/sendgrid/open',
                    'click' => $base . '/webhooks/sendgrid/click',
                ],
                'amazon-ses' => [
                    'sns' => $base . '/ses/sns',
                ],
                'resend' => [
                    'webhook' => $base . '/webhooks/resend',
                    'bounce' => $base . '/webhooks/resend/bounce',
                    'open' => $base . '/webhooks/resend/open',
                    'click' => $base . '/webhooks/resend/click',
                    'delivered' => $base . '/webhooks/resend/delivered',
                ],
            };

            $settings = $deliveryServer->settings ?? [];
            if ($type === 'amazon-ses') {
                $existing = is_array($settings['webhooks'] ?? null) ? $settings['webhooks'] : [];
                unset($existing['bounce'], $existing['open'], $existing['click']);
                $settings['webhooks'] = array_merge($existing, $urls);
            } else {
                $settings['webhooks'] = array_merge($settings['webhooks'] ?? [], $urls);
            }
            $deliveryServer->update(['settings' => $settings]);
        } catch (\Throwable $e) {
        }
    }

    protected function sendSparkPostApiTestEmail(?DeliveryServer $server, array $data, string $fromEmail, string $fromName = ''): void
    {
        $rawKeyCandidates = $server
            ? [
                'settings.secret' => $server->settings['secret'] ?? null,
                'settings.api_key' => $server->settings['api_key'] ?? null,
                'server.password' => $server->password,
                'services.sparkpost.secret' => config('services.sparkpost.secret'),
            ]
            : [
                'request.api_key' => $data['api_key'] ?? null,
                'request.api_secret' => $data['api_secret'] ?? null,
                'services.sparkpost.secret' => config('services.sparkpost.secret'),
            ];

        Log::info('SparkPost test email key candidates', [
            'server_id' => $server?->id,
            'raw_key_candidates' => $rawKeyCandidates,
        ]);

        $keyCandidates = [];
        foreach ($rawKeyCandidates as $source => $rawKey) {
            $normalized = $this->normalizeSparkPostApiKey($rawKey);
            if ($normalized !== '' && !in_array($normalized, array_column($keyCandidates, 'key'), true)) {
                $keyCandidates[] = [
                    'source' => $source,
                    'key' => $normalized,
                ];
            }
        }

        $endpoint = $server
            ? (($server->settings['endpoint'] ?? null)
                ?? $server->hostname
                ?? config('services.sparkpost.endpoint'))
            : (($data['api_hostname'] ?? null)
                ?? ($data['hostname'] ?? null)
                ?? config('services.sparkpost.endpoint'));

        if (empty($keyCandidates)) {
            Log::error('SparkPost test email: No API key found', [
                'raw_key_candidates' => $rawKeyCandidates,
                'server_id' => $server?->id,
            ]);
            throw new \Exception('SparkPost configuration incomplete: API key is required.');
        }

        $baseUrl = $this->normalizeSparkPostApiBaseUrl($endpoint);
        $endpointCandidates = [$baseUrl];
        if ($baseUrl === 'https://api.sparkpost.com') {
            $endpointCandidates[] = 'https://api.eu.sparkpost.com';
        } elseif ($baseUrl === 'https://api.eu.sparkpost.com') {
            $endpointCandidates[] = 'https://api.sparkpost.com';
        }

        $rawBody = (string) ($data['message'] ?? '');
        $looksLikeHtml = preg_match('/<\s*\w+[^>]*>/', $rawBody) === 1;
        $htmlBody = $looksLikeHtml
            ? $rawBody
            : '<div style="white-space: pre-wrap;">' . nl2br(htmlspecialchars($rawBody, ENT_QUOTES, 'UTF-8')) . '</div>';
        $textBody = trim(preg_replace('/\s+/', ' ', strip_tags($rawBody)));

        $payload = [
            'content' => [
                'from' => [
                    'email' => $fromEmail,
                    'name' => $fromName !== '' ? $fromName : null,
                ],
                'subject' => (string) ($data['subject'] ?? 'This is a Test Email'),
                'html' => $htmlBody,
                'text' => $textBody !== '' ? $textBody : null,
            ],
            'recipients' => [
                [
                    'address' => [
                        'email' => (string) $data['to_email'],
                    ],
                ],
            ],
        ];

        $attemptErrors = [];
        foreach ($endpointCandidates as $endpointCandidate) {
            foreach ($keyCandidates as $candidate) {
                $response = $this->sendSparkPostTransmissionWithHttp($endpointCandidate, $candidate['key'], $payload);

                if ($response->successful()) {
                    return;
                }

                $errorBody = $response->body();
                if (mb_strlen($errorBody) > 500) {
                    $errorBody = mb_substr($errorBody, 0, 500) . '...';
                }

                $attemptErrors[] = [
                    'endpoint' => $endpointCandidate,
                    'source' => $candidate['source'],
                    'status' => $response->status(),
                    'body' => $errorBody,
                ];

                if ($response->status() !== 401) {
                    throw new \Exception('SparkPost API request failed (HTTP ' . $response->status() . ', endpoint: ' . $endpointCandidate . ', key source: ' . $candidate['source'] . '): ' . $errorBody);
                }
            }
        }

        $sourceEndpointPairs = implode(', ', array_map(static fn ($e) => $e['source'] . '@' . $e['endpoint'], $attemptErrors));
        $last = end($attemptErrors);
        $lastBody = is_array($last) ? ($last['body'] ?? 'Unauthorized.') : 'Unauthorized.';

        throw new \Exception('SparkPost API request failed (HTTP 401): ' . $lastBody . ' Endpoints tried: ' . implode(', ', $endpointCandidates) . '. Key sources tried: ' . $sourceEndpointPairs . '.');
    }

    protected function sendSparkPostTransmissionWithHttp(string $endpointBaseUrl, string $apiKey, array $payload): \Illuminate\Http\Client\Response
    {
        $transmissionsUrl = rtrim($endpointBaseUrl, '/') . '/api/v1/transmissions';

        return Http::timeout(20)
            ->withHeaders([
                'Authorization' => $apiKey,
                'Content-Type' => 'application/json',
                'Accept' => 'application/json',
            ])
            ->post($transmissionsUrl, $payload);
    }

    protected function normalizeSparkPostApiBaseUrl(mixed $endpoint): string
    {
        $value = is_string($endpoint) ? trim($endpoint) : '';

        if (str_contains($value, 'smtp.sparkpostmail.com')) {
            $value = str_replace('smtp.sparkpostmail.com', 'api.sparkpost.com', $value);
        }

        if (str_contains($value, 'smtp.eu.sparkpostmail.com')) {
            $value = str_replace('smtp.eu.sparkpostmail.com', 'api.eu.sparkpost.com', $value);
        }

        if ($value === '') {
            return 'https://api.sparkpost.com';
        }

        if (!str_starts_with($value, 'http://') && !str_starts_with($value, 'https://')) {
            $value = 'https://' . $value;
        }

        $value = rtrim($value, '/');

        if (str_ends_with($value, '/api/v1/transmissions')) {
            $value = substr($value, 0, -strlen('/api/v1/transmissions'));
        } elseif (str_ends_with($value, '/api/v1')) {
            $value = substr($value, 0, -strlen('/api/v1'));
        }

        return rtrim($value, '/');
    }

    protected function normalizeSparkPostApiKey(mixed $secret): string
    {
        $value = is_string($secret) ? trim($secret) : '';

        if (str_starts_with(strtolower($value), 'bearer ')) {
            $value = trim(substr($value, 7));
        }

        return $value;
    }

    /**
     * Get paginated list of delivery servers.
     */
    public function getPaginated(array $filters = [], int $perPage = 15): LengthAwarePaginator
    {
        $query = DeliveryServer::query();
        $workspaceId = session('active_workspace_id');

        if ($workspaceId) {
            $query->where(function ($sub) use ($workspaceId) {
                $sub->where('workspace_id', $workspaceId)
                    ->orWhereNull('workspace_id');
            });
        }

        if (array_key_exists('customer_id', $filters)) {
            if ($filters['customer_id'] === null) {
                $query->whereNull('customer_id');
            } else {
                $query->where('customer_id', $filters['customer_id']);
            }
        }

        // Apply filters
        if (isset($filters['search'])) {
            $search = $filters['search'];
            $query->where(function ($q) use ($search) {
                $q->where('name', 'like', "%{$search}%")
                    ->orWhere('hostname', 'like', "%{$search}%")
                    ->orWhere('from_email', 'like', "%{$search}%");
            });
        }

        if (isset($filters['type'])) {
            $query->where('type', $filters['type']);
        }

        if (isset($filters['status'])) {
            $query->where('status', $filters['status']);
        }

        return $query->latest()->paginate($perPage);
    }

    /**
     * Create a new delivery server.
     */
    public function create(array $data): DeliveryServer
    {
        $settings = $data['settings'] ?? [];

        $type = $data['type'] ?? 'smtp';
        $isSmtpLike = in_array($type, ['smtp', 'zeptomail'], true);

        $port = array_key_exists('port', $data) ? $data['port'] : null;
        if ($port === null && $isSmtpLike) {
            $port = 587;
        }

        $encryption = $this->normalizeEncryptionValue($data['encryption'] ?? null, $type);

        $attributes = [
            'customer_id' => $data['customer_id'] ?? null,
            'name' => $data['name'],
            'type' => $type,
            'status' => $data['status'] ?? 'pending',
            'hostname' => $data['hostname'] ?? null,
            'username' => $data['username'] ?? null,
            'password' => $data['password'] ?? null,
            'from_email' => $data['from_email'] ?? null,
            'from_name' => $data['from_name'] ?? null,
            'reply_to_email' => $data['reply_to_email'] ?? null,
            'timeout' => $data['timeout'] ?? 30,
            'max_connection_messages' => $data['max_connection_messages'] ?? 100,
            'second_quota' => $data['second_quota'] ?? 0,
            'minute_quota' => $data['minute_quota'] ?? 0,
            'hourly_quota' => $data['hourly_quota'] ?? 0,
            'daily_quota' => $data['daily_quota'] ?? 0,
            'monthly_quota' => $data['monthly_quota'] ?? 0,
            'pause_after_send' => $data['pause_after_send'] ?? 0,
            'settings' => $settings,
            'locked' => $data['locked'] ?? false,
            'use_for' => $data['use_for'] ?? true,
            'use_for_email_to_list' => $data['use_for_email_to_list'] ?? false,
            'use_for_transactional' => $data['use_for_transactional'] ?? false,
            'bounce_server_id' => $data['bounce_server_id'] ?? null,
            'tracking_domain_id' => $data['tracking_domain_id'] ?? null,
            'notes' => $data['notes'] ?? null,
        ];

        if ($port !== null) {
            $attributes['port'] = $port;
        }

        if ($encryption !== null) {
            $attributes['encryption'] = $encryption;
        }

        // Create the delivery server
        $deliveryServer = DeliveryServer::create($attributes);

        // Setup webhook for API-based servers
        if ($deliveryServer->type === 'mailgun') {
            $this->setupMailgunWebhook($deliveryServer, $data);
        }
        if ($deliveryServer->type === 'resend') {
            $this->setupResendWebhook($deliveryServer);
        }

        $this->ensureProviderWebhooksStored($deliveryServer);

        // Only SMTP-like servers require verification
        if (
            in_array($deliveryServer->type, ['smtp', 'gmail', 'outlook'], true)
            && !empty($deliveryServer->username)
            && filter_var($deliveryServer->username, FILTER_VALIDATE_EMAIL)
        ) {
            try {
                $this->sendVerificationEmail($deliveryServer);
            } catch (\Throwable $e) {
                Log::warning('Automatic verification email send failed after delivery server creation', [
                    'server_id' => $deliveryServer->id,
                    'email' => $deliveryServer->username,
                    'hostname' => $deliveryServer->hostname,
                    'error' => $e->getMessage(),
                    'exception' => get_class($e),
                ]);
            }
        }

        return $deliveryServer;
    }

    /**
     * Update an existing delivery server.
     */
    public function update(DeliveryServer $deliveryServer, array $data): DeliveryServer
    {
        if (array_key_exists('settings', $data)) {
            $existingSettings = is_array($deliveryServer->settings) ? $deliveryServer->settings : [];
            $incomingSettings = is_array($data['settings']) ? $data['settings'] : [];

            foreach (['secret', 'api_key', 'token', 'key', 'send_mail_token'] as $secretKey) {
                if (!array_key_exists($secretKey, $incomingSettings)) {
                    continue;
                }

                $value = $incomingSettings[$secretKey];
                $isMasked = is_string($value) && trim($value) === '********';
                $isBlank = $value === null || (is_string($value) && trim($value) === '');

                if (($isMasked || $isBlank) && array_key_exists($secretKey, $existingSettings)) {
                    $incomingSettings[$secretKey] = $existingSettings[$secretKey];
                }
            }

            $data['settings'] = array_replace($existingSettings, $incomingSettings);
        }

        $currentType = (string) ($data['type'] ?? $deliveryServer->type ?? 'smtp');

        if (array_key_exists('port', $data) && $data['port'] === null) {
            unset($data['port']);
        }

        if (array_key_exists('encryption', $data)) {
            $data['encryption'] = $this->normalizeEncryptionValue($data['encryption'], $currentType);
        } elseif (!is_string($deliveryServer->encryption) || trim($deliveryServer->encryption) === '' || !in_array(strtolower(trim($deliveryServer->encryption)), ['ssl', 'tls', 'none'], true)) {
            $data['encryption'] = $this->normalizeEncryptionValue(null, $currentType);
        }

        $deliveryServer->update($data);
        $deliveryServer->refresh();

        // Setup/update webhook for API-based servers
        if ($deliveryServer->type === 'mailgun') {
            $this->setupMailgunWebhook($deliveryServer, $data);
        }
        if ($deliveryServer->type === 'resend') {
            $this->setupResendWebhook($deliveryServer);
        }

        $this->ensureProviderWebhooksStored($deliveryServer);

        return $deliveryServer->fresh();
    }

    public function setPrimary(DeliveryServer $deliveryServer): DeliveryServer
    {
        return DB::transaction(function () use ($deliveryServer) {
            DeliveryServer::query()
                ->when($deliveryServer->customer_id === null, function ($q) {
                    $q->whereNull('customer_id');
                }, function ($q) use ($deliveryServer) {
                    $q->where('customer_id', $deliveryServer->customer_id);
                })
                ->where('id', '!=', $deliveryServer->id)
                ->update(['is_primary' => false]);

            $deliveryServer->update(['is_primary' => true]);

            return $deliveryServer->fresh();
        });
    }

    /**
     * Delete a delivery server.
     */
    public function delete(DeliveryServer $deliveryServer): bool
    {
        // Delete webhooks for API-based servers
        if ($deliveryServer->type === 'mailgun') {
            $this->deleteMailgunWebhook($deliveryServer);
        }
        if ($deliveryServer->type === 'resend') {
            $this->deleteResendWebhook($deliveryServer);
        }

        $id = $deliveryServer->id;

        // Null out delivery_server_id on campaigns that reference this server
        DB::table('campaigns')->where('delivery_server_id', $id)->update(['delivery_server_id' => null]);

        // Remove pivot allocations so the server no longer appears in customer dropdowns
        if (Schema::hasTable('customer_delivery_server')) {
            DB::table('customer_delivery_server')->where('delivery_server_id', $id)->delete();
        }
        if (Schema::hasTable('customer_group_delivery_server')) {
            DB::table('customer_group_delivery_server')->where('delivery_server_id', $id)->delete();
        }

        return $deliveryServer->delete();
    }

    /**
     * Setup Mailgun webhook for a delivery server.
     */
    protected function setupMailgunWebhook(DeliveryServer $deliveryServer, array $data): void
    {
        try {
            $webhookService = app(MailgunWebhookService::class);
            $settings = $deliveryServer->settings ?? [];

            // Get domain and API key from settings or data
            $domain = $settings['domain'] ?? $data['settings']['domain'] ?? null;
            $apiKey = $settings['secret'] ?? $data['settings']['secret'] ?? config('services.mailgun.secret');

            // If using SMTP, try to extract domain from hostname or from_email
            if (!$domain && !empty($deliveryServer->hostname)) {
                // Mailgun SMTP hostname is usually smtp.mailgun.org or smtp.eu.mailgun.org
                // Domain should be in settings or from_email
                $domain = $settings['domain'] ?? null;
            }

            if (!$domain && !empty($deliveryServer->from_email)) {
                // Extract domain from from_email as fallback
                $domain = substr(strrchr($deliveryServer->from_email, "@"), 1);
            }

            if (!$domain || !$apiKey) {
                Log::warning("Cannot setup Mailgun webhook: missing domain or API key", [
                    'server_id' => $deliveryServer->id,
                    'has_domain' => !empty($domain),
                    'has_api_key' => !empty($apiKey),
                ]);
                return;
            }

            // Generate webhook ID (unique per server)
            $baseUrl = rtrim((string) config('app.url'), '/');
            $webhookMap = [
                'bounced' => $baseUrl . '/webhooks/mailgun/bounce',
                'failed' => $baseUrl . '/webhooks/mailgun/bounce',
                'opened' => $baseUrl . '/webhooks/mailgun/open',
                'clicked' => $baseUrl . '/webhooks/mailgun/click',
            ];

            $results = [];
            foreach ($webhookMap as $eventName => $url) {
                $results[$eventName] = $webhookService->createOrUpdateWebhook(
                    $domain,
                    $apiKey,
                    $eventName,
                    $url
                );
            }

            $settings['mailgun_webhooks'] = [
                'domain' => $domain,
                'configured_at' => now()->toIso8601String(),
                'events' => array_keys($webhookMap),
                'urls' => $webhookMap,
            ];
            $deliveryServer->update(['settings' => $settings]);

            Log::info("Mailgun webhooks configured", [
                'server_id' => $deliveryServer->id,
                'domain' => $domain,
                'success' => collect($results)->every(fn ($r) => ($r['success'] ?? false) === true),
            ]);
        } catch (\Exception $e) {
            Log::error("Exception setting up Mailgun webhook: " . $e->getMessage(), [
                'server_id' => $deliveryServer->id,
                'trace' => $e->getTraceAsString(),
            ]);
        }
    }

    /**
     * Delete Mailgun webhook when server is deleted.
     */
    protected function deleteMailgunWebhook(DeliveryServer $deliveryServer): void
    {
        try {
            $settings = $deliveryServer->settings ?? [];
            $webhookInfo = $settings['mailgun_webhooks'] ?? null;

            $webhookService = app(MailgunWebhookService::class);
            $domain = $webhookInfo['domain'] ?? $settings['domain'] ?? null;
            $apiKey = $settings['secret'] ?? config('services.mailgun.secret');

            if (!$domain || !$apiKey) {
                return;
            }

            $events = $webhookInfo['events'] ?? ['bounced', 'failed', 'opened', 'clicked'];
            foreach ($events as $eventName) {
                if (!is_string($eventName) || trim($eventName) === '') {
                    continue;
                }
                $webhookService->deleteWebhook($domain, $apiKey, trim($eventName));
            }

            Log::info("Mailgun webhooks deleted", [
                'server_id' => $deliveryServer->id,
                'domain' => $domain,
            ]);
        } catch (\Exception $e) {
            Log::error("Exception deleting Mailgun webhook: " . $e->getMessage(), [
                'server_id' => $deliveryServer->id,
            ]);
        }
    }

    /**
     * Setup Resend webhook for a delivery server via Resend API.
     */
    protected function setupResendWebhook(DeliveryServer $deliveryServer): void
    {
        try {
            $settings = $deliveryServer->settings ?? [];
            $apiKey = $settings['api_key'] ?? null;
            $endpoint = rtrim($settings['endpoint'] ?? 'https://api.resend.com', '/');

            if (!$apiKey) {
                Log::warning('Cannot setup Resend webhook: missing API key', [
                    'server_id' => $deliveryServer->id,
                ]);
                return;
            }

            $baseUrl = rtrim((string) config('app.url'), '/');
            // Resend requires HTTPS webhook URLs
            $webhookUrl = str_replace('http://', 'https://', $baseUrl) . '/webhooks/resend';
            $events = [
                'email.sent',
                'email.delivered',
                'email.delivery_delayed',
                'email.bounced',
                'email.opened',
                'email.clicked',
                'email.complained',
            ];

            $client = Http::timeout(20)
                ->withHeaders([
                    'Authorization' => 'Bearer ' . $apiKey,
                    'Content-Type' => 'application/json',
                    'Accept' => 'application/json',
                ]);

            // List existing webhooks to find one with matching URL
            $existingWebhookId = null;
            $listResponse = $client->get($endpoint . '/webhooks');
            if ($listResponse->successful()) {
                $webhooks = $listResponse->json('data') ?? [];
                foreach ($webhooks as $webhook) {
                    $webhookUrlField = $webhook['url'] ?? $webhook['endpoint'] ?? '';
                    if ($webhookUrlField === $webhookUrl) {
                        $existingWebhookId = $webhook['id'] ?? null;
                        break;
                    }
                }
            }

            $payload = [
                'endpoint' => $webhookUrl,
                'events' => $events,
            ];

            if ($existingWebhookId) {
                $response = $client->patch($endpoint . '/webhooks/' . $existingWebhookId, $payload);
            } else {
                $response = $client->post($endpoint . '/webhooks', $payload);
            }

            if (!$response->successful()) {
                Log::error('Failed to ' . ($existingWebhookId ? 'update' : 'create') . ' Resend webhook', [
                    'server_id' => $deliveryServer->id,
                    'status' => $response->status(),
                    'body' => $response->body(),
                ]);
                return;
            }

            $result = $response->json();
            $webhookId = $result['id'] ?? $existingWebhookId ?? null;
            $webhookSecret = $result['secret'] ?? null;

            if ($webhookId) {
                $settings['resend_webhook_id'] = $webhookId;
            }
            if ($webhookSecret) {
                $settings['webhook_secret'] = $webhookSecret;
            }
            $settings['resend_webhook_url'] = $webhookUrl;
            $settings['resend_webhook_events'] = $events;
            $settings['resend_webhook_configured_at'] = now()->toIso8601String();

            $deliveryServer->update(['settings' => $settings]);

            Log::info('Resend webhook ' . ($existingWebhookId ? 'updated' : 'created'), [
                'server_id' => $deliveryServer->id,
                'webhook_id' => $webhookId,
            ]);
        } catch (\Exception $e) {
            Log::error('Exception setting up Resend webhook: ' . $e->getMessage(), [
                'server_id' => $deliveryServer->id,
                'trace' => $e->getTraceAsString(),
            ]);
        }
    }

    /**
     * Delete Resend webhook when server is deleted.
     */
    protected function deleteResendWebhook(DeliveryServer $deliveryServer): void
    {
        try {
            $settings = $deliveryServer->settings ?? [];
            $webhookId = $settings['resend_webhook_id'] ?? null;
            $apiKey = $settings['api_key'] ?? null;
            $endpoint = rtrim($settings['endpoint'] ?? 'https://api.resend.com', '/');

            if (!$webhookId || !$apiKey) {
                return;
            }

            $response = Http::timeout(20)
                ->withHeaders([
                    'Authorization' => 'Bearer ' . $apiKey,
                    'Accept' => 'application/json',
                ])
                ->delete($endpoint . '/webhooks/' . $webhookId);

            if (!$response->successful() && $response->status() !== 404) {
                Log::warning('Failed to delete Resend webhook', [
                    'server_id' => $deliveryServer->id,
                    'webhook_id' => $webhookId,
                    'status' => $response->status(),
                ]);
                return;
            }

            Log::info('Resend webhook deleted', [
                'server_id' => $deliveryServer->id,
                'webhook_id' => $webhookId,
            ]);
        } catch (\Exception $e) {
            Log::error('Exception deleting Resend webhook: ' . $e->getMessage(), [
                'server_id' => $deliveryServer->id,
            ]);
        }
    }

    /**
     * Test SMTP/API connection and send test email.
     */
    public function testConnection(array $data): array
    {
        Log::info('Starting SMTP/API connection test', [
            'test_type' => $data['test_type'] ?? 'unknown',
            'server_id' => $data['server_id'] ?? null,
            'type' => $data['type'] ?? null,
        ]);

        $testTimeoutSeconds = 8;
        $previousSocketTimeout = ini_get('default_socket_timeout');
        if ($previousSocketTimeout !== false) {
            @ini_set('default_socket_timeout', (string) $testTimeoutSeconds);
        }

        $server = null;
        
        try {
            if ($data['test_type'] === 'server') {
                $server = DeliveryServer::findOrFail($data['server_id']);
                Log::info('Using existing delivery server', [
                    'server_id' => $server->id,
                    'server_name' => $server->name,
                    'server_type' => $server->type,
                    'hostname' => $server->hostname,
                    'port' => $server->port,
                ]);
            } else {
                Log::info('Using manual configuration', [
                    'type' => $data['type'] ?? 'unknown',
                    'hostname' => $data['hostname'] ?? null,
                    'port' => $data['port'] ?? null,
                ]);
            }

            // Configure mail based on server or manual settings
            if ($server) {
                $this->configureMailFromServer($server);
                Log::info('Configuring mail from server');

                // API providers reject mail unless the From domain is verified on the
                // provider account. Falling back to the global MAIL_FROM_ADDRESS (which
                // usually belongs to a different domain) produces a confusing rejection,
                // so require an explicit From Email on these servers instead.
                if (in_array($server->type, ['resend', 'sparkpost', 'mailgun', 'sendgrid', 'postmark'], true)
                    && (!is_string($server->from_email) || trim((string) $server->from_email) === '')) {
                    throw new \Exception('This ' . ucfirst($server->type) . ' server has no From Email set. Edit the server and set a From Email on a domain verified in your ' . ucfirst($server->type) . ' account.');
                }

                $fromEmail = $server->from_email ?? config('mail.from.address');
                $fromName = $server->from_name ?? config('mail.from.name');
            } else {
                Log::info('Configuring mail from manual settings');
                $manualType = (string) ($data['type'] ?? 'smtp');
                $manualEncryption = $this->normalizeEncryptionValue($data['encryption'] ?? null, $manualType);
                if ($manualEncryption === 'none') {
                    $manualEncryption = null;
                }
                $data['encryption'] = $manualEncryption;
                $this->configureMailFromManual($data);
                $fromEmail = $data['from_email'] ?? config('mail.from.address');
                $fromName = $data['from_name'] ?? config('mail.from.name');
            }

            if (!is_string($fromEmail) || trim($fromEmail) === '') {
                throw new \Exception('Sender email is not configured. Please set MAIL_FROM_ADDRESS (or configure From Email on the selected delivery server).');
            }

            // Log mail configuration (without sensitive data)
            Log::info('Mail configuration set', [
                'default_mailer' => config('mail.default'),
                'from_email' => $fromEmail,
                'from_name' => $fromName,
                'to_email' => $data['to_email'],
                'subject' => $data['subject'],
                'mailgun_domain' => config('services.mailgun.domain'),
                'mailgun_secret_exists' => !empty(config('services.mailgun.secret')),
                'smtp_host' => config('mail.mailers.smtp.host'),
                'smtp_port' => config('mail.mailers.smtp.port'),
            ]);

            try {
                if (config('mail.default') === 'smtp') {
                    $smtpHost = (string) config('mail.mailers.smtp.host');
                    $smtpPort = (int) config('mail.mailers.smtp.port');

                    if ($server && in_array($server->type, ['smtp', 'gmail', 'outlook', 'zeptomail', 'mailjet'], true)) {
                        $smtpHost = (string) ($server->hostname ?? '');
                        $smtpPort = (int) ($server->port ?? $smtpPort);
                    }

                    if (trim($smtpHost) === '') {
                        throw new \Exception('SMTP preflight failed: host is empty for the selected delivery server. Please set a valid SMTP hostname.');
                    }

                    if ($smtpPort <= 0) {
                        $smtpPort = 587;
                    }

                    $resolved = @gethostbynamel($smtpHost);
                    $resolved = is_array($resolved) ? $resolved : [];

                    $fp = @fsockopen($smtpHost, $smtpPort > 0 ? $smtpPort : 587, $errno, $errstr, $testTimeoutSeconds);
                    $tcpConnectOk = is_resource($fp);
                    if ($tcpConnectOk) {
                        fclose($fp);
                    }

                    Log::info('SMTP preflight check for test email', [
                        'host' => $smtpHost,
                        'port' => $smtpPort,
                        'dns_a' => $resolved,
                        'tcp_connect_ok' => $tcpConnectOk,
                        'tcp_errno' => $errno ?? null,
                        'tcp_errstr' => $errstr ?? null,
                    ]);

                    if (!$tcpConnectOk) {
                        Log::warning('SMTP preflight TCP connect failed (non-fatal, will attempt send anyway)', [
                            'host' => $smtpHost,
                            'port' => $smtpPort,
                            'errno' => $errno ?? null,
                            'errstr' => $errstr ?? null,
                        ]);
                    }
                }
            } catch (\Throwable $e) {
                Log::warning('SMTP preflight check error (non-fatal)', [
                    'error' => $e->getMessage(),
                ]);
            }

            // Send test email
            Log::info('Attempting to send test email');

            if ($server && $server->type === 'zeptomail-api') {
                $rawBody = (string) ($data['message'] ?? '');
                $looksLikeHtml = preg_match('/<\s*\w+[^>]*>/', $rawBody) === 1;
                $htmlBody = $looksLikeHtml
                    ? $rawBody
                    : '<div style="white-space: pre-wrap;">' . nl2br(htmlspecialchars($rawBody, ENT_QUOTES, 'UTF-8')) . '</div>';
                $textBody = trim(preg_replace('/\s+/', ' ', strip_tags($rawBody)));

                $zepto = app(ZeptoMailApiService::class);
                $message = [
                    'from_email' => (string) $fromEmail,
                    'from_name' => (string) $fromName,
                    'to_email' => (string) $data['to_email'],
                    'subject' => (string) $data['subject'],
                    'htmlbody' => $htmlBody,
                    'textbody' => $textBody,
                    'client_reference' => 'delivery-server-test-' . $server->id,
                ];

                $server->loadMissing('bounceServer');
                if (empty(($server->settings ?? [])['bounce_address']) && !empty($server->bounceServer?->username)) {
                    $message['bounce_address'] = (string) $server->bounceServer->username;
                }

                $zepto->sendRaw($server, $message);

                Log::info('Test email sent successfully (ZeptoMail API)', [
                    'from' => $fromEmail,
                    'to' => $data['to_email'],
                    'subject' => $data['subject'],
                ]);

                return [
                    'from' => $fromEmail,
                    'to' => $data['to_email'],
                    'subject' => $data['subject'],
                    'server_type' => $server->type,
                ];
            }

            if ($server && $server->type === 'emailit') {
                $rawBody = (string) ($data['message'] ?? '');
                $looksLikeHtml = preg_match('/<\s*\w+[^>]*>/', $rawBody) === 1;
                $htmlBody = $looksLikeHtml
                    ? $rawBody
                    : '<div style="white-space: pre-wrap;">' . nl2br(htmlspecialchars($rawBody, ENT_QUOTES, 'UTF-8')) . '</div>';
                $textBody = trim(preg_replace('/\s+/', ' ', strip_tags($rawBody)));

                $emailit = app(EmailitApiService::class);
                $message = [
                    'from_email' => (string) $fromEmail,
                    'from_name' => (string) $fromName,
                    'subject' => (string) $data['subject'],
                    'htmlbody' => $htmlBody,
                    'textbody' => $textBody,
                ];

                $emailit->send($server, $message);

                Log::info('Test email sent successfully (Emailit API)', [
                    'from' => $fromEmail,
                    'to' => $data['to_email'],
                    'subject' => $data['subject'],
                ]);

                return [
                    'from' => $fromEmail,
                    'to' => $data['to_email'],
                    'subject' => $data['subject'],
                    'server_type' => $server->type,
                ];
            }

            $isSparkPost = ($server && $server->type === 'sparkpost')
                || (!$server && (($data['type'] ?? null) === 'sparkpost'));

            if ($isSparkPost) {
                $this->sendSparkPostApiTestEmail($server, $data, (string) $fromEmail, (string) ($fromName ?? ''));

                Log::info('Test email sent successfully (SparkPost API)', [
                    'from' => $fromEmail,
                    'to' => $data['to_email'],
                    'subject' => $data['subject'],
                ]);

                return [
                    'from' => $fromEmail,
                    'to' => $data['to_email'],
                    'subject' => $data['subject'],
                    'server_type' => $server ? $server->type : $data['type'],
                    'test_type' => $data['test_type'],
                    'transport' => 'sparkpost-api',
                ];
            }

            if ($server) {
                $this->configureMailFromServer($server);
            }

            // Ensure test email fails fast on network issues (avoid hitting PHP max_execution_time)
            try {
                $smtpMailer = (array) (config('mail.mailers.smtp') ?? []);
                $smtpMailer['timeout'] = $testTimeoutSeconds;
                \Illuminate\Support\Facades\Config::set('mail.mailers.smtp', $smtpMailer);
            } catch (\Throwable $e) {
                // ignore
            }

            try {
                app('mail.manager')->forgetMailers();
                app('mail.manager')->purge('smtp');
            } catch (\Throwable $e) {
                Log::warning('Unable to reset cached mailers before SMTP test send', [
                    'error' => $e->getMessage(),
                ]);
            }

            // Apply SSL stream options directly to the Symfony SocketStream.
            // Laravel's configureSmtpTransport() ignores the 'stream' config key —
            // SSL options must be set on the transport's SocketStream after it is built.
            try {
                if (!env('MAIL_VERIFY_PEER', true)) {
                    $builtMailer = app('mail.manager')->mailer(config('mail.default', 'smtp'));
                    $symfonyTransport = $builtMailer->getSymfonyTransport();
                    if ($symfonyTransport instanceof \Symfony\Component\Mailer\Transport\Smtp\EsmtpTransport) {
                        $socketStream = $symfonyTransport->getStream();
                        if ($socketStream instanceof \Symfony\Component\Mailer\Transport\Smtp\Stream\SocketStream) {
                            $socketStream->setStreamOptions([
                                'ssl' => [
                                    'verify_peer'       => false,
                                    'verify_peer_name'  => false,
                                    'allow_self_signed' => true,
                                ],
                            ]);
                            Log::info('SSL certificate verification disabled for test SMTP send');
                        }
                    }
                }
            } catch (\Throwable $e) {
                Log::warning('Unable to configure SSL stream options for SMTP transport', [
                    'error' => $e->getMessage(),
                ]);
            }
            
            // Load bounce server if server exists and has bounce_server_id
            $bounceServer = null;
            if ($server && $server->bounce_server_id) {
                $server->load('bounceServer');
                $bounceServer = $server->bounceServer;
                
                // Only use bounce server if it's active and has a username (email address)
                if ($bounceServer && $bounceServer->isActive() && !empty($bounceServer->username)) {
                    Log::info('Bounce server found for test email', [
                        'bounce_server_id' => $bounceServer->id,
                        'bounce_server_name' => $bounceServer->name,
                        'bounce_email' => $bounceServer->username,
                    ]);
                } else {
                    $bounceServer = null; // Reset if not active or missing username
                }
            }

            $rawBody = (string) ($data['message'] ?? '');
            $looksLikeHtml = preg_match('/<\s*\w+[^>]*>/', $rawBody) === 1;
            $htmlBody = $looksLikeHtml
                ? $rawBody
                : '<div style="white-space: pre-wrap;">' . nl2br(htmlspecialchars($rawBody, ENT_QUOTES, 'UTF-8')) . '</div>';
            $textBody = trim(preg_replace('/\s+/', ' ', strip_tags($rawBody)));

            Mail::send([], [], function ($message) use ($data, $fromEmail, $fromName, $bounceServer, $htmlBody, $textBody) {
                $message->to($data['to_email'])
                    ->subject($data['subject'])
                    ->from($fromEmail, $fromName);

                // Set Return-Path header if bounce server is configured and active
                if ($bounceServer && !empty($bounceServer->username)) {
                    $message->returnPath($bounceServer->username);
                    Log::info('Added Return-Path header to test email', [
                        'return_path' => $bounceServer->username,
                    ]);
                }

                if (!empty($htmlBody)) {
                    $message->html($htmlBody);
                }

                if (!empty($textBody)) {
                    $message->text($textBody);
                }
            });

            Log::info('Test email sent successfully', [
                'from' => $fromEmail,
                'to' => $data['to_email'],
                'subject' => $data['subject'],
            ]);

            if ($server) {
                DeliveryServerLog::create([
                    'delivery_server_id' => $server->id,
                    'event' => 'test_sent',
                    'to_email' => $data['to_email'],
                    'status' => 'success',
                    'meta' => ['from' => $fromEmail, 'subject' => $data['subject']],
                ]);
            }

            return [
                'from' => $fromEmail,
                'to' => $data['to_email'],
                'subject' => $data['subject'],
                'server_type' => $server ? $server->type : $data['type'],
                'test_type' => $data['test_type'],
            ];
        } catch (\Swift_TransportException $e) {
            Log::error('Swift Transport Exception during email test', [
                'error' => $e->getMessage(),
                'code' => $e->getCode(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
            ]);
            $this->logDeliveryError($server, $data, 'test_failed', $e->getMessage());
            throw new \Exception('SMTP Connection Error: ' . $e->getMessage(), 0, $e);
        } catch (\Exception $e) {
            Log::error('Exception during email test', [
                'error' => $e->getMessage(),
                'code' => $e->getCode(),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
                'trace' => $e->getTraceAsString(),
                'mail_config' => [
                    'default' => config('mail.default'),
                    'smtp_host' => config('mail.mailers.smtp.host'),
                    'smtp_port' => config('mail.mailers.smtp.port'),
                    'smtp_encryption' => config('mail.mailers.smtp.encryption'),
                    'smtp_username' => config('mail.mailers.smtp.username') ? '***' : null,
                ],
            ]);
            $this->logDeliveryError($server, $data, 'test_failed', $e->getMessage());
            throw $e;
        } finally {
            if ($previousSocketTimeout !== false) {
                @ini_set('default_socket_timeout', (string) $previousSocketTimeout);
            }
        }
    }

    /**
     * Configure mail settings from delivery server.
     */
    public function configureMailFromServer(DeliveryServer $server, ?string $sendingDomainOverride = null): void
    {
        Log::info('Configuring mail from server', [
            'server_type' => $server->type,
            'server_id' => $server->id,
            'sending_domain_override' => $sendingDomainOverride,
        ]);

        // Forget any previously-resolved mailer so the new config is picked up.
        try {
            Mail::purge();
        } catch (\Throwable $e) {
            // Fallback for versions without purge()
        }

        try {
            $systemId = Setting::get('system_smtp_delivery_server_id');
            if ($systemId && (int) $systemId === (int) $server->id) {
                $this->configureMailFromSystemSmtp();
                return;
            }
        } catch (\Throwable $e) {
            // ignore
        }

        switch ($server->type) {
            case 'smtp':
            case 'gmail':
            case 'outlook':
            case 'zeptomail':
                if (empty($server->hostname)) {
                    throw new \RuntimeException('Delivery server "' . $server->name . '" has no hostname configured. Please update the server settings.');
                }
                $encryption = $this->normalizeEncryptionValue($server->encryption, (string) $server->type);
                if ($encryption === 'none') {
                    $encryption = null;
                }
                Log::info('Configuring SMTP settings', [
                    'host' => $server->hostname,
                    'port' => $server->port ?? 587,
                    'encryption' => $encryption ?? 'tls',
                    'username' => $server->username,
                    'has_password' => !empty($server->password),
                ]);
                Config::set('mail.mailers.smtp', [
                    'transport' => 'smtp',
                    'host' => $server->hostname,
                    'port' => $server->port ?? 587,
                    'encryption' => $encryption,
                    'username' => $server->username,
                    'password' => $server->password,
                    'stream' => $this->smtpStreamOptions(),
                    'timeout' => $server->timeout ?? 30,
                ]);
                Config::set('mail.default', 'smtp');
                break;

            case 'mailgun':
                $settings = $server->settings ?? [];
                
                // Check if Mailgun has API credentials (domain and secret)
                $domain = $sendingDomainOverride ?: ($settings['domain'] ?? config('services.mailgun.domain'));
                $secret = $settings['secret'] ?? $settings['api_key'] ?? config('services.mailgun.secret');
                
                Log::info('Mailgun configuration check', [
                    'server_id' => $server->id,
                    'domain' => $domain,
                    'secret_exists' => !empty($secret),
                    'hostname' => $server->hostname,
                    'username' => $server->username,
                    'password_exists' => !empty($server->password),
                    'settings_domain' => $settings['domain'] ?? null,
                    'settings_secret' => $settings['secret'] ?? null,
                    'settings_api_key' => $settings['api_key'] ?? null,
                ]);
                
                if (!empty($domain) && !empty($secret)) {
                    // Use API configuration for Mailgun (prioritize API over SMTP)
                    if (!class_exists('Symfony\\Component\\Mailer\\Bridge\\Mailgun\\Transport\\MailgunTransportFactory')) {
                        throw new \Exception('Mailgun mail transport is not installed. Install symfony/mailgun-mailer and symfony/http-client to send via Mailgun API.');
                    }

                    Log::info('Configuring Mailgun API settings', [
                        'domain' => $domain,
                        'has_secret' => !empty($secret),
                        'endpoint' => $settings['endpoint'] ?? config('services.mailgun.endpoint', 'api.mailgun.net'),
                    ]);
                    
                    Config::set('services.mailgun', [
                        'domain' => $domain,
                        'secret' => $secret,
                        'endpoint' => $settings['endpoint'] ?? config('services.mailgun.endpoint', 'api.mailgun.net'),
                    ]);
                    Config::set('mail.default', 'mailgun');
                    
                    Log::info('Mailgun configured to use API', [
                        'mail_default' => config('mail.default'),
                        'services_mailgun_domain' => config('services.mailgun.domain'),
                    ]);
                } elseif (!empty($server->hostname) && !empty($server->username) && !empty($server->password)) {
                    // Use SMTP configuration for Mailgun as fallback
                    Log::info('Configuring Mailgun SMTP settings', [
                        'host' => $server->hostname,
                        'port' => $server->port ?? 587,
                        'encryption' => $server->encryption ?? 'tls',
                        'username' => $server->username,
                        'has_password' => !empty($server->password),
                    ]);
                    Config::set('mail.mailers.smtp', [
                        'transport' => 'smtp',
                        'host' => $server->hostname,
                        'port' => $server->port ?? 587,
                        'encryption' => $server->encryption ?? 'tls',
                        'username' => $server->username,
                        'password' => $server->password,
                        'stream' => $this->smtpStreamOptions(),
                        'timeout' => $server->timeout ?? 30,
                    ]);
                    Config::set('mail.default', 'smtp');
                    
                    Log::info('Mailgun configured to use SMTP', [
                        'mail_default' => config('mail.default'),
                    ]);
                } else {
                    Log::warning('Mailgun configuration incomplete', [
                        'has_domain' => !empty($domain),
                        'has_secret' => !empty($secret),
                        'has_hostname' => !empty($server->hostname),
                        'has_username' => !empty($server->username),
                        'has_password' => !empty($server->password),
                    ]);
                    throw new \Exception('Mailgun configuration incomplete: Provide either API credentials (domain and API key) or SMTP credentials (hostname, username, password).');
                }
                break;

            case 'sendgrid':
                $settings = $server->settings ?? [];
                Config::set('services.sendgrid', [
                    'api_key' => $settings['api_key'] ?? config('services.sendgrid.api_key'),
                ]);
                if (!config('mail.mailers.sendgrid')) {
                    Config::set('mail.mailers.sendgrid', ['transport' => 'sendgrid']);
                }
                Config::set('mail.default', 'sendgrid');
                break;

            case 'postmark':
                $settings = $server->settings ?? [];
                Config::set('services.postmark', [
                    'token' => $settings['token'] ?? config('services.postmark.token'),
                ]);
                Config::set('mail.default', 'postmark');
                break;

            case 'amazon-ses':
                $settings = $server->settings ?? [];
                Config::set('services.ses', [
                    'key' => $settings['key'] ?? config('services.ses.key'),
                    'secret' => $settings['secret'] ?? config('services.ses.secret'),
                    'region' => $settings['region'] ?? config('services.ses.region', 'us-east-1'),
                ]);
                
                // Use custom SES transport that supports ReplyToAddresses
                Config::set('mail.mailers.ses-reply-to', [
                    'transport' => 'ses-reply-to',
                    'key' => $settings['key'] ?? config('services.ses.key'),
                    'secret' => $settings['secret'] ?? config('services.ses.secret'),
                    'region' => $settings['region'] ?? config('services.ses.region', 'us-east-1'),
                    'options' => $settings['options'] ?? [],
                ]);
                
                Config::set('mail.default', 'ses-reply-to');
                break;

            case 'sparkpost':
                $settings = $server->settings ?? [];
                Log::info('SparkPost server settings', [
                    'server_id' => $server->id,
                    'settings_keys' => array_keys($settings),
                    'has_secret' => isset($settings['secret']),
                    'has_api_key' => isset($settings['api_key']),
                    'has_password' => !empty($server->password),
                ]);
                $secret = $settings['secret']
                    ?? $settings['api_key']
                    ?? $server->password
                    ?? config('services.sparkpost.secret');
                $endpoint = $settings['endpoint']
                    ?? $server->hostname
                    ?? config('services.sparkpost.endpoint');
                Log::info('Configuring SparkPost settings', [
                    'endpoint' => $endpoint,
                    'has_secret' => !empty($secret),
                ]);

                if (empty($secret)) {
                    throw new \Exception('SparkPost configuration incomplete: API key is required.');
                }

                Config::set('services.sparkpost', [
                    'secret' => $secret,
                    'endpoint' => $endpoint,
                ]);
                Config::set('mail.default', 'sparkpost');
                break;

            case 'mailjet':
                $settings = $server->settings ?? [];
                $apiKey = $settings['key'] ?? $server->username;
                $apiSecret = $settings['secret'] ?? $server->password;
                
                Log::info('Configuring Mailjet settings from server', [
                    'host' => $server->hostname ?? 'in-v3.mailjet.com',
                    'port' => $server->port ?? 587,
                    'encryption' => $server->encryption ?? 'tls',
                    'has_key' => !empty($apiKey),
                    'has_secret' => !empty($apiSecret),
                ]);
                
                if (empty($apiKey) || empty($apiSecret)) {
                    Log::warning('Mailjet configuration incomplete', [
                        'has_key' => !empty($apiKey),
                        'has_secret' => !empty($apiSecret),
                    ]);
                    throw new \Exception('Mailjet configuration incomplete: API Key and API Secret are required.');
                }
                
                // Mailjet uses SMTP with API key/secret as username/password
                Config::set('mail.mailers.smtp', [
                    'transport' => 'smtp',
                    'host' => $server->hostname ?? 'in-v3.mailjet.com',
                    'port' => $server->port ?? 587,
                    'encryption' => $server->encryption ?? 'tls',
                    'username' => $apiKey,
                    'password' => $apiSecret,
                    'stream' => $this->smtpStreamOptions(),
                    'timeout' => $server->timeout ?? 30,
                ]);
                Config::set('mail.default', 'smtp');
                break;

            case 'resend':
                $settings = (array) ($server->settings ?? []);
                $apiKey = $settings['api_key']
                    ?? $settings['secret']
                    ?? $settings['key']
                    ?? $server->password
                    ?? config('services.resend.api_key');

                if (empty($apiKey)) {
                    throw new \Exception('Resend configuration incomplete: API key is required.');
                }

                $endpoint = $settings['endpoint'] ?? $server->hostname ?? 'https://api.resend.com';

                Config::set('services.resend', [
                    'api_key' => $apiKey,
                    'endpoint' => $endpoint,
                ]);
                Config::set('mail.mailers.resend', [
                    'transport' => 'resend',
                    'api_key' => $apiKey,
                    'endpoint' => $endpoint,
                ]);
                Config::set('mail.default', 'resend');
                break;

            case 'gmail-api':
                $settings = (array) ($server->settings ?? []);
                Config::set('mail.mailers.gmail-api', [
                    'transport' => 'gmail-api',
                    'client_id' => $settings['client_id'] ?? '',
                    'client_secret' => $settings['client_secret'] ?? '',
                    'refresh_token' => $settings['refresh_token'] ?? '',
                ]);
                Config::set('mail.default', 'gmail-api');
                break;

            case 'sendmail':
                Log::info('Configuring Sendmail');
                Config::set('mail.default', 'sendmail');
                break;

            case 'emailit':
                Log::info('Emailit API server configured (no mailer transport required)');
                break;

            default:
                throw new \RuntimeException('Unsupported delivery server type "' . $server->type . '" for server "' . $server->name . '".');
        }
        
        // Log final mail configuration
        Log::info('Mail configuration completed', [
            'default_mailer' => config('mail.default'),
            'smtp_host' => config('mail.mailers.smtp.host'),
            'smtp_port' => config('mail.mailers.smtp.port'),
        ]);
    }

    /**
     * Log a delivery error to the delivery_server_logs table.
     */
    protected function logDeliveryError(?DeliveryServer $server, array $data, string $event, string $errorMessage): void
    {
        if (!$server) {
            return;
        }

        try {
            $category = DeliveryServerLog::categorizeError($errorMessage);

            DeliveryServerLog::create([
                'delivery_server_id' => $server->id,
                'event' => $event,
                'to_email' => $data['to_email'] ?? null,
                'status' => 'failed',
                'error_code' => $this->extractErrorCode($errorMessage),
                'error_message' => mb_substr($errorMessage, 0, 1000),
                'diagnostic' => $errorMessage,
                'error_category' => $category,
                'meta' => [
                    'from' => $data['from_email'] ?? ($server->from_email ?? null),
                    'subject' => $data['subject'] ?? null,
                ],
            ]);
        } catch (\Throwable $e) {
            Log::warning('Failed to log delivery server error', [
                'server_id' => $server->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Extract SMTP error code from an error message string.
     */
    protected function extractErrorCode(string $message): ?string
    {
        if (preg_match('/\b(\d{3}[-\s]\d\.\d\.\d+)\b/', $message, $m)) {
            return $m[1];
        }
        if (preg_match('/\b(\d{3})\b/', $message, $m)) {
            return $m[1];
        }
        return null;
    }

    protected function smtpStreamOptions(): array
    {
        return [
            'ssl' => [
                'verify_peer' => (bool) env('MAIL_VERIFY_PEER', true),
                'verify_peer_name' => (bool) env('MAIL_VERIFY_PEER_NAME', true),
                'allow_self_signed' => (bool) env('MAIL_ALLOW_SELF_SIGNED', false),
            ],
        ];
    }

    public function hasSystemSmtpConfigured(): bool
    {
        $existing = $this->getStoredSystemSmtpDeliveryServer();
        if ($existing) {
            return true;
        }

        $host = env('MAIL_HOST');
        if (!is_string($host)) {
            return false;
        }

        return trim($host) !== '';
    }

    public function getStoredSystemSmtpDeliveryServer(): ?DeliveryServer
    {
        try {
            $existingId = Setting::get('system_smtp_delivery_server_id');
            if ($existingId && DeliveryServer::query()->whereKey((int) $existingId)->exists()) {
                return DeliveryServer::query()->whereKey((int) $existingId)->first();
            }
        } catch (\Throwable $e) {
            // ignore
        }

        return DeliveryServer::query()
            ->whereNull('customer_id')
            ->where('name', 'System (SMTP)')
            ->orderBy('id')
            ->first();
    }

    public function getSystemSmtpServerStub(): object
    {
        $systemServer = $this->getOrCreateSystemSmtpDeliveryServer();

        $host = (string) env('MAIL_HOST', '');
        $port = (int) env('MAIL_PORT', 587);
        $encryption = (string) env('MAIL_ENCRYPTION', 'tls');
        $username = env('MAIL_USERNAME');

        $fromEmail = Setting::get('from_email', env('MAIL_FROM_ADDRESS'));
        $fromName = Setting::get('from_name', env('MAIL_FROM_NAME', env('APP_NAME', 'MailPurse')));

        return (object) [
            'is_system' => true,
            'id' => $systemServer?->id,
            'name' => 'System (SMTP)',
            'type' => 'smtp',
            'status' => 'active',
            'hostname' => $host,
            'port' => $port > 0 ? $port : 587,
            'encryption' => $encryption,
            'username' => is_string($username) ? $username : null,
            'from_email' => is_string($fromEmail) ? $fromEmail : null,
            'from_name' => is_string($fromName) ? $fromName : null,
            'monthly_quota' => 0,
            'is_primary' => false,
            'locked' => true,
            'use_for' => (bool) ($systemServer?->use_for ?? false),
            'use_for_transactional' => (bool) ($systemServer?->use_for_transactional ?? false),
            'use_for_email_to_list' => (bool) ($systemServer?->use_for_email_to_list ?? false),
        ];
    }

    public function getOrCreateSystemSmtpDeliveryServer(): ?DeliveryServer
    {
        $existing = $this->getStoredSystemSmtpDeliveryServer();
        if ($existing) {
            try {
                Setting::set('system_smtp_delivery_server_id', (int) $existing->id, 'email', 'integer');
            } catch (\Throwable $e) {
                // ignore
            }

            return $existing;
        }

        if (!$this->hasSystemSmtpConfigured()) {
            return null;
        }

        $server = DeliveryServer::query()->create([
            'customer_id' => null,
            'name' => 'System (SMTP)',
            'type' => 'smtp',
            'status' => 'active',
            'hostname' => (string) env('MAIL_HOST', ''),
            'port' => (int) env('MAIL_PORT', 587),
            'username' => env('MAIL_USERNAME'),
            'password' => env('MAIL_PASSWORD'),
            'encryption' => $this->normalizeEncryptionValue(env('MAIL_ENCRYPTION', 'tls'), 'smtp'),
            'from_email' => Setting::get('from_email', env('MAIL_FROM_ADDRESS')),
            'from_name' => Setting::get('from_name', env('MAIL_FROM_NAME', env('APP_NAME', 'MailPurse'))),
            'timeout' => (int) env('MAIL_TIMEOUT', 30),
            'max_connection_messages' => 100,
            'second_quota' => 0,
            'minute_quota' => 0,
            'hourly_quota' => 0,
            'daily_quota' => 0,
            'monthly_quota' => 0,
            'pause_after_send' => 0,
            'settings' => ['system_env_seeded' => true],
            'locked' => true,
            'use_for' => false,
            'use_for_email_to_list' => false,
            'use_for_transactional' => false,
        ]);

        try {
            Setting::set('system_smtp_delivery_server_id', (int) $server->id, 'email', 'integer');
        } catch (\Throwable $e) {
            // ignore
        }

        return $server;
    }

    /**
     * Update system server configuration from environment variables.
     */
    public function updateSystemServerFromEnv(DeliveryServer $server): void
    {
        if (!$this->hasSystemSmtpConfigured()) {
            return;
        }

        $host = (string) env('MAIL_HOST', '');
        $port = (int) env('MAIL_PORT', 587);
        $encryption = $this->normalizeEncryptionValue(env('MAIL_ENCRYPTION', 'tls'), 'smtp');
        $username = env('MAIL_USERNAME');

        $server->update([
            'hostname' => $host,
            'port' => $port > 0 ? $port : 587,
            'encryption' => $encryption,
            'username' => is_string($username) ? $username : null,
        ]);
    }

    public function configureMailFromSystemSmtp(?DeliveryServer $server = null): void
    {
        $server ??= $this->getStoredSystemSmtpDeliveryServer();

        if ($server && is_string($server->hostname) && trim($server->hostname) !== '') {
            $encryption = $server->encryption;
            if (!is_string($encryption) || trim($encryption) === '' || strtolower(trim($encryption)) === 'none') {
                $encryption = null;
            }

            Config::set('mail.mailers.smtp', [
                'transport' => 'smtp',
                'host' => (string) $server->hostname,
                'port' => (int) ($server->port ?? 587),
                'encryption' => $encryption,
                'username' => $server->username,
                'password' => $server->password,
                'stream' => $this->smtpStreamOptions(),
                'timeout' => (int) ($server->timeout ?? 30),
            ]);
            Config::set('mail.default', 'smtp');
            return;
        }

        $host = env('MAIL_HOST');
        if (!is_string($host) || trim($host) === '') {
            return;
        }

        $encryption = env('MAIL_ENCRYPTION', 'tls');
        if (!is_string($encryption) || trim($encryption) === '' || strtolower(trim($encryption)) === 'none') {
            $encryption = null;
        }

        Config::set('mail.mailers.smtp', [
            'transport' => 'smtp',
            'host' => (string) $host,
            'port' => (int) env('MAIL_PORT', 587),
            'encryption' => $encryption,
            'username' => env('MAIL_USERNAME'),
            'password' => env('MAIL_PASSWORD'),
            'stream' => $this->smtpStreamOptions(),
            'timeout' => (int) env('MAIL_TIMEOUT', 30),
        ]);
        Config::set('mail.default', 'smtp');
    }

    /**
     * Normalize an encryption value into one of the supported database values.
     */
    protected function normalizeEncryptionValue(mixed $value, ?string $type = null): string
    {
        if (is_string($value)) {
            $value = strtolower(trim($value));
            if (in_array($value, ['ssl', 'tls', 'none'], true)) {
                return $value;
            }
        }

        $type = strtolower(trim((string) $type));
        if ($type === 'sendmail') {
            return 'none';
        }

        return 'tls';
    }

    /**
     * Configure mail settings from manual input.
     */
    protected function configureMailFromManual(array $data): void
    {
        Log::info('Configuring mail from manual input', [
            'type' => $data['type'] ?? 'unknown',
        ]);

        $encryption = $this->normalizeEncryptionValue($data['encryption'] ?? null, (string) ($data['type'] ?? 'smtp'));
        if ($encryption === 'none') {
            $encryption = null;
        }

        switch ($data['type']) {
            case 'smtp':
            case 'gmail':
            case 'outlook':
            case 'zeptomail':
                Log::info('Configuring manual SMTP settings', [
                    'host' => $data['hostname'] ?? null,
                    'port' => $data['port'] ?? 587,
                    'encryption' => $encryption ?? 'tls',
                    'username' => $data['username'] ?? null,
                    'has_password' => !empty($data['password']),
                ]);
                Config::set('mail.mailers.smtp', [
                    'transport' => 'smtp',
                    'host' => $data['hostname'],
                    'port' => $data['port'] ?? 587,
                    'encryption' => $encryption,
                    'username' => $data['username'],
                    'password' => $data['password'],
                    'stream' => $this->smtpStreamOptions(),
                    'timeout' => 30,
                ]);
                Config::set('mail.default', 'smtp');
                break;

            case 'mailgun':
                // Check if API credentials are provided (domain and api_key)
                // or SMTP credentials (hostname, username, password)
                $hasApiCredentials = (!empty($data['hostname']) || !empty($data['api_hostname'])) && !empty($data['api_key']);
                $hasSmtpCredentials = !empty($data['hostname']) && !empty($data['username']) && !empty($data['password']);
                
                if ($hasApiCredentials) {
                    // Use API configuration for Mailgun (prioritize API over SMTP)
                    $domain = $data['hostname'] ?? $data['api_hostname'] ?? config('services.mailgun.domain');
                    $secret = $data['api_key'] ?? config('services.mailgun.secret');
                    
                    Log::info('Configuring Mailgun via API', [
                        'domain' => $domain,
                        'has_secret' => !empty($secret),
                    ]);
                    
                    Config::set('services.mailgun', [
                        'domain' => $domain,
                        'secret' => $secret,
                    ]);
                    Config::set('mail.default', 'mailgun');
                } elseif ($hasSmtpCredentials) {
                    // Use SMTP configuration for Mailgun as fallback
                    Log::info('Configuring Mailgun via SMTP', [
                        'host' => $data['hostname'],
                        'port' => $data['port'] ?? 587,
                        'username' => $data['username'],
                        'has_password' => !empty($data['password']),
                    ]);
                    
                    Config::set('mail.mailers.smtp', [
                        'transport' => 'smtp',
                        'host' => $data['hostname'],
                        'port' => $data['port'] ?? 587,
                        'encryption' => $encryption,
                        'username' => $data['username'],
                        'password' => $data['password'],
                        'stream' => $this->smtpStreamOptions(),
                        'timeout' => 30,
                    ]);
                    Config::set('mail.default', 'smtp');
                } else {
                    Log::warning('Mailgun configuration incomplete', [
                        'has_smtp' => $hasSmtpCredentials,
                        'has_api' => $hasApiCredentials,
                    ]);
                    throw new \Exception('Mailgun configuration incomplete. Provide either API credentials (domain and API key) or SMTP credentials (hostname, username, password).');
                }
                break;

            case 'sendgrid':
                Config::set('services.sendgrid', [
                    'api_key' => $data['api_key'] ?? config('services.sendgrid.api_key'),
                ]);
                if (!config('mail.mailers.sendgrid')) {
                    Config::set('mail.mailers.sendgrid', ['transport' => 'sendgrid']);
                }
                Config::set('mail.default', 'sendgrid');
                break;

            case 'postmark':
                Config::set('services.postmark', [
                    'token' => $data['api_key'] ?? config('services.postmark.token'),
                ]);
                Config::set('mail.default', 'postmark');
                break;

            case 'amazon-ses':
                Config::set('services.ses', [
                    'key' => $data['api_key'] ?? config('services.ses.key'),
                    'secret' => $data['api_secret'] ?? config('services.ses.secret'),
                    'region' => $data['hostname'] ?? $data['api_hostname'] ?? config('services.ses.region', 'us-east-1'),
                ]);
                Config::set('mail.default', 'ses');
                break;

            case 'sparkpost':
                $secret = $data['api_key']
                    ?? $data['api_secret']
                    ?? config('services.sparkpost.secret');
                $endpoint = $data['api_hostname']
                    ?? $data['hostname']
                    ?? config('services.sparkpost.endpoint');
                Log::info('Configuring manual SparkPost settings', [
                    'endpoint' => $endpoint,
                    'has_secret' => !empty($secret),
                ]);

                if (empty($secret)) {
                    throw new \Exception('SparkPost configuration incomplete: API key is required.');
                }

                Config::set('services.sparkpost', [
                    'secret' => $secret,
                    'endpoint' => $endpoint,
                ]);
                Config::set('mail.default', 'sparkpost');
                break;

            case 'mailjet':
                Log::info('Configuring manual Mailjet settings', [
                    'host' => $data['hostname'] ?? 'in-v3.mailjet.com',
                    'port' => $data['port'] ?? 587,
                    'has_key' => !empty($data['api_key']),
                    'has_secret' => !empty($data['api_secret']),
                ]);
                // Mailjet uses SMTP with API key/secret as username/password
                Config::set('mail.mailers.smtp', [
                    'transport' => 'smtp',
                    'host' => $data['hostname'] ?? 'in-v3.mailjet.com',
                    'port' => $data['port'] ?? 587,
                    'encryption' => $encryption,
                    'username' => $data['api_key'] ?? $data['username'],
                    'password' => $data['api_secret'] ?? $data['password'],
                    'stream' => $this->smtpStreamOptions(),
                    'timeout' => 30,
                ]);
                Config::set('mail.default', 'smtp');
                break;

            case 'sendmail':
                Log::info('Configuring manual Sendmail');
                Config::set('mail.default', 'sendmail');
                break;
        }
    }

    /**
     * Send verification email to delivery server's SMTP account email (username).
     * Uses the delivery server's own SMTP configuration to verify it can send emails.
     */
    public function sendVerificationEmail(DeliveryServer $deliveryServer): bool
    {
        try {
            // Use username as the SMTP account email
            $smtpEmail = $deliveryServer->username;
            
            // Only send if username is a valid email address
            if (empty($smtpEmail) || !filter_var($smtpEmail, FILTER_VALIDATE_EMAIL)) {
                Log::warning("Cannot send verification email: username is not a valid email", [
                    'server_id' => $deliveryServer->id,
                    'username' => $smtpEmail,
                ]);
                return false;
            }

            // Only send for SMTP-like servers (not sendmail, API-based servers, etc.)
            if (!in_array($deliveryServer->type, ['smtp', 'gmail', 'outlook'], true)) {
                Log::info("Skipping verification email for non-SMTP server", [
                    'server_id' => $deliveryServer->id,
                    'type' => $deliveryServer->type,
                ]);
                return false;
            }

            // Validate required SMTP settings
            if (empty($deliveryServer->hostname) || empty($deliveryServer->username) || empty($deliveryServer->password)) {
                Log::warning("Cannot send verification email: missing SMTP configuration", [
                    'server_id' => $deliveryServer->id,
                    'has_hostname' => !empty($deliveryServer->hostname),
                    'has_username' => !empty($deliveryServer->username),
                    'has_password' => !empty($deliveryServer->password),
                ]);
                return false;
            }

            // Generate verification token if not exists
            if (!$deliveryServer->verification_token) {
                $deliveryServer->generateVerificationToken();
                $deliveryServer->refresh();
            }

            // Refresh to get the latest token
            $deliveryServer->refresh();

            // Configure mailer using THIS delivery server's settings
            $mailerName = 'verification_' . $deliveryServer->id;

            $port = $deliveryServer->port ?? 587;
            $encryption = $deliveryServer->encryption ?? 'tls';
            $scheme = null;

            if ($encryption === 'none') {
                $encryption = null;
                $scheme = 'smtp';
            }
            
            Config::set("mail.mailers.{$mailerName}", [
                'transport' => 'smtp',
                'scheme' => $scheme,
                'host' => $deliveryServer->hostname,
                'port' => $port,
                'username' => $deliveryServer->username,
                'password' => $deliveryServer->password,
                'encryption' => $encryption,
                'stream' => $this->smtpStreamOptions(),
                'timeout' => $deliveryServer->timeout ?? 30,
            ]);

            Log::info("Attempting to send verification email using delivery server's own SMTP config", [
                'server_id' => $deliveryServer->id,
                'email' => $smtpEmail,
                'hostname' => $deliveryServer->hostname,
                'port' => $deliveryServer->port,
                'encryption' => $deliveryServer->encryption,
                'token' => substr($deliveryServer->verification_token, 0, 10) . '...',
            ]);

            try {
                $host = (string) $deliveryServer->hostname;
                $portForLog = (int) ($deliveryServer->port ?? 0);
                $resolved = @gethostbynamel($host);
                $resolved = is_array($resolved) ? $resolved : [];
                $fp = @fsockopen($host, $portForLog > 0 ? $portForLog : 587, $errno, $errstr, 6);
                if (is_resource($fp)) {
                    fclose($fp);
                }

                Log::info('SMTP preflight check for verification email', [
                    'server_id' => $deliveryServer->id,
                    'host' => $host,
                    'port' => $portForLog,
                    'dns_a' => $resolved,
                    'tcp_connect_ok' => is_resource($fp),
                    'tcp_errno' => $errno ?? null,
                    'tcp_errstr' => $errstr ?? null,
                ]);
            } catch (\Throwable $e) {
                Log::info('SMTP preflight check failed (non-fatal)', [
                    'server_id' => $deliveryServer->id,
                    'error' => $e->getMessage(),
                ]);
            }

            // Use the delivery server's own mailer configuration
            Mail::mailer($mailerName)
                ->to($smtpEmail)
                ->send(new DeliveryServerVerificationMailable($deliveryServer));

            Log::info("Verification email sent successfully using delivery server's SMTP", [
                'server_id' => $deliveryServer->id,
                'email' => $smtpEmail,
                'hostname' => $deliveryServer->hostname,
            ]);

            return true;
        } catch (\Symfony\Component\Mailer\Exception\TransportExceptionInterface $e) {
            Log::error("SMTP transport error sending verification email: " . $e->getMessage(), [
                'server_id' => $deliveryServer->id,
                'email' => $deliveryServer->username,
                'hostname' => $deliveryServer->hostname,
                'error_code' => $e->getCode(),
                'exception' => get_class($e),
            ]);
            return false;
        } catch (\Swift_TransportException $e) {
            Log::error("SMTP Transport error sending verification email: " . $e->getMessage(), [
                'server_id' => $deliveryServer->id,
                'email' => $deliveryServer->username,
                'hostname' => $deliveryServer->hostname,
                'error_code' => $e->getCode(),
                'exception' => get_class($e),
            ]);
            return false;
        } catch (\Exception $e) {
            Log::error("Failed to send verification email for delivery server: " . $e->getMessage(), [
                'server_id' => $deliveryServer->id,
                'email' => $deliveryServer->username,
                'hostname' => $deliveryServer->hostname,
                'exception' => get_class($e),
                'file' => $e->getFile(),
                'line' => $e->getLine(),
            ]);
            return false;
        }
    }

    /**
     * Verify delivery server using token.
     */
    public function verify(string $token): ?DeliveryServer
    {
        $deliveryServer = DeliveryServer::where('verification_token', $token)
            ->whereNull('verified_at')
            ->first();

        if (!$deliveryServer) {
            return null;
        }

        // Check if token is expired (7 days)
        $createdAt = $deliveryServer->created_at;
        if ($createdAt && $createdAt->addDays(7)->isPast()) {
            Log::warning("Verification token expired", [
                'server_id' => $deliveryServer->id,
            ]);
            return null;
        }

        $deliveryServer->markAsVerified();

        Log::info("Delivery server verified", [
            'server_id' => $deliveryServer->id,
        ]);

        return $deliveryServer;
    }
}