| null */ public ?array $data = []; protected static ?string $title = 'Imap Settings'; protected static string|BackedEnum|null $navigationIcon = Heroicon::OutlinedEnvelope; // Uncomment if you want to set a custom navigation icon // protected ?string $subheading = ''; // Uncomment if you want to set a custom subheading // protected static ?string $slug = 'imap-settings'; // Uncomment if you want to set a custom slug protected string $view = 'filament.pages.imap-settings'; protected function settingName(): string { return 'imap'; } /** * Provide default values. * * @return array */ public function getDefaultData(): array { return [ 'public.default_account' => 'default', 'public.protocol' => 'imap', 'premium.default_email' => 'default', 'premium.protocol' => 'imap', ]; } public function getHeaderActions(): array { return [ Action::make('test_connection') ->label('Test Connection') ->color('gray') ->icon('heroicon-o-paper-airplane') ->action(fn () => $this->testIMAPConnection()), ...parent::getHeaderActions(), ]; } public function form(Schema $schema): Schema { return $schema ->components([ Section::make('Public Mailbox Imap') ->description('Enter your imap server') ->collapsible() ->schema([ TextInput::make('public.host')->label('Hostname')->required(), TextInput::make('public.port')->label('Port')->required(), Select::make('public.encryption')->options([ 'none' => 'None', 'ssl' => 'SSL', 'tls' => 'TLS', ]), Checkbox::make('public.validate_cert')->label('Validate Encryption Certificate')->default(false), TextInput::make('public.username')->label('Username')->required(), TextInput::make('public.password')->label('Password')->required(), TextInput::make('public.default_account')->label('Default Account')->placeholder('default'), TextInput::make('public.protocol')->label('Protocol')->placeholder('imap'), Checkbox::make('public.cc_check')->label('Check CC Field')->default(false)->helperText('If enabled, we will check the CC field as well while fetching mails.'), ]), Section::make('Premium Mailbox Imap') ->description('Enter your imap server') ->collapsed() ->schema([ TextInput::make('premium.host')->label('Hostname')->required(), TextInput::make('premium.port')->label('Port')->required(), Select::make('premium.encryption')->options([ 'none' => 'None', 'ssl' => 'SSL', 'tls' => 'TLS', ]), Checkbox::make('premium.validate_cert')->label('Validate Encryption Certificate')->default(false), TextInput::make('premium.username')->label('Username')->required(), TextInput::make('premium.password')->label('Password')->required(), TextInput::make('premium.default_account')->label('Default Account')->placeholder('default'), TextInput::make('premium.protocol')->label('Protocol')->placeholder('imap'), Checkbox::make('premium.cc_check')->label('Check CC Field')->default(false)->helperText('If enabled, we will check the CC field as well while fetching mails.'), ]), ]) ->statePath('data'); } private function testIMAPConnection(): void { $settings = $this->data; $results = []; $hasSuccess = false; $hasFailure = false; // Define IMAP configuration sections - easy to extend $imapSections = ['public', 'premium']; foreach ($imapSections as $sectionName) { $sectionConfig = $this->getImapSectionConfig($settings, $sectionName); $result = $this->testSingleImapConnection($sectionName, $sectionConfig); $results[] = $result; if ($result['success']) { $hasSuccess = true; } else { $hasFailure = true; } } // Send appropriate notification based on results $this->sendImapTestNotification($results, $hasSuccess, $hasFailure); } /** * Get IMAP section configuration for a specific parent key. */ private function getImapSectionConfig(array $settings, string $sectionName): array { $config = []; $fields = ['host', 'port', 'username', 'password', 'encryption', 'validate_cert', 'protocol']; foreach ($fields as $field) { $key = $sectionName.'.'.$field; // Try different data structure approaches $value = null; // 1. Direct key access (flat structure with dots) if (isset($settings[$key])) { $value = $settings[$key]; } // 2. Nested structure access elseif (isset($settings[$sectionName][$field])) { $value = $settings[$sectionName][$field]; } // 3. Alternative nested structure elseif (isset($settings[$sectionName]) && is_array($settings[$sectionName])) { $nested = $settings[$sectionName]; if (isset($nested[$field])) { $value = $nested[$field]; } } $config[$field] = $value; } return $config; } /** * Test a single IMAP connection configuration. */ private function testSingleImapConnection(string $sectionName, array $config): array { $requiredFields = ['host', 'port', 'username', 'password']; // Check for missing required fields $missingFields = collect($requiredFields)->filter(fn ($field): bool => empty($config[$field])); if ($missingFields->isNotEmpty()) { return [ 'section' => ucfirst($sectionName), 'success' => false, 'message' => 'Missing required fields: '.$missingFields->join(', '), 'details' => null, ]; } try { // First check if IMAP extension is available if (! function_exists('imap_open')) { return [ 'section' => ucfirst($sectionName), 'success' => false, 'message' => 'IMAP extension is not loaded in your web server. Please check your Herd PHP configuration or restart your server.', 'details' => null, ]; } // Build IMAP configuration array in the format ZEmail expects $imapConfig = [ 'host' => $config['host'], 'port' => (int) $config['port'], 'username' => $config['username'], 'password' => $config['password'], 'encryption' => $config['encryption'] ?? 'none', 'validate_cert' => $config['validate_cert'] ?? false, 'protocol' => $config['protocol'] ?? 'imap', ]; // Test connection using the existing ZEmail::connectMailBox method ZEmail::connectMailBox($imapConfig); return [ 'section' => ucfirst($sectionName), 'success' => true, 'message' => 'Connection successful', 'details' => [ 'host' => $config['host'], 'port' => $config['port'], 'encryption' => $config['encryption'] ?? 'none', 'protocol' => $config['protocol'] ?? 'imap', ], ]; } catch (\Exception $e) { $errorMessage = $e->getMessage(); // Provide more helpful error messages if (str_contains($errorMessage, 'IMAP extension must be enabled')) { $errorMessage = 'IMAP extension is not properly loaded in the web server. Try restarting Herd or check your PHP configuration.'; } return [ 'section' => ucfirst($sectionName), 'success' => false, 'message' => $errorMessage, 'details' => [ 'host' => $config['host'] ?? null, 'port' => $config['port'] ?? null, 'encryption' => $config['encryption'] ?? 'none', 'protocol' => $config['protocol'] ?? 'imap', ], ]; } } /** * Send appropriate notification based on test results. */ private function sendImapTestNotification(array $results, bool $hasSuccess, bool $hasFailure): void { $totalTests = count($results); $successCount = count(array_filter($results, fn ($r): bool => $r['success'])); if ($hasSuccess && ! $hasFailure) { // All successful Notification::make() ->title("All IMAP connections successful! ({$successCount}/{$totalTests})") ->success() ->body($this->formatSuccessNotification($results)) ->send(); } elseif (! $hasSuccess && $hasFailure) { // All failed Notification::make() ->title("All IMAP connections failed (0/{$totalTests})") ->danger() ->body($this->formatFailureNotification($results)) ->send(); } else { // Mixed results Notification::make() ->title("IMAP connection test completed ({$successCount}/{$totalTests} successful)") ->warning() ->body($this->formatMixedNotification($results)) ->send(); } } /** * Format success notification details. */ private function formatSuccessNotification(array $results): string { $details = []; foreach ($results as $result) { if ($result['success'] && isset($result['details']['messages'])) { $details[] = "{$result['section']}: {$result['details']['messages']} messages"; } } return implode(' | ', $details); } /** * Format failure notification details. */ private function formatFailureNotification(array $results): string { $details = []; foreach ($results as $result) { $details[] = "{$result['section']}: {$result['message']}"; } return implode(' | ', $details); } /** * Format mixed results notification details. */ private function formatMixedNotification(array $results): string { $details = []; foreach ($results as $result) { $status = $result['success'] ? '✅' : '❌'; $details[] = "{$status} {$result['section']}"; } return implode(' | ', $details); } }