getStream(); $stream->disableTls(); } $transport->setUsername($username); $transport->setPassword($password); // 연결 시도 (타임아웃 10초) $transport->start(); $responseTimeMs = (int) ((microtime(true) - $startTime) * 1000); // 테스트 메일 발송 (선택) $testMailSent = false; if ($testRecipient) { $testMailSent = $this->sendTestMail($transport, $username, $testRecipient); } $transport->stop(); return [ 'success' => true, 'message' => 'SMTP 연결 성공', 'response_time_ms' => $responseTimeMs, 'server_banner' => $host.':'.$port, 'error_code' => null, 'test_mail_sent' => $testMailSent, ]; } catch (\Symfony\Component\Mailer\Exception\TransportExceptionInterface $e) { $responseTimeMs = (int) ((microtime(true) - $startTime) * 1000); return $this->parseTransportError($e, $responseTimeMs); } catch (\Exception $e) { $responseTimeMs = (int) ((microtime(true) - $startTime) * 1000); return [ 'success' => false, 'message' => '연결 실패: '.$e->getMessage(), 'response_time_ms' => $responseTimeMs, 'server_banner' => null, 'error_code' => 'UNKNOWN', ]; } } /** * Laravel Mail 파사드를 사용한 SMTP 연결 테스트 (대체 방식) */ public function testViaLaravel( string $host, int $port, string $encryption, string $username, string $password, ?string $testRecipient = null ): array { $startTime = microtime(true); try { $config = [ 'transport' => 'smtp', 'host' => $host, 'port' => $port, 'encryption' => $encryption, 'username' => $username, 'password' => $password, 'timeout' => 10, ]; $transport = \Illuminate\Support\Facades\Mail::createSymfonyTransport($config); $transport->start(); $responseTimeMs = (int) ((microtime(true) - $startTime) * 1000); $testMailSent = false; if ($testRecipient) { $testMailSent = $this->sendTestMailViaLaravel($config, $testRecipient, $username); } $transport->stop(); return [ 'success' => true, 'message' => 'SMTP 연결 성공', 'response_time_ms' => $responseTimeMs, 'server_banner' => $host.':'.$port, 'error_code' => null, 'test_mail_sent' => $testMailSent, ]; } catch (\Exception $e) { $responseTimeMs = (int) ((microtime(true) - $startTime) * 1000); return $this->parseError($e, $responseTimeMs); } } private function sendTestMail($transport, string $from, string $to): bool { try { $email = (new \Symfony\Component\Mime\Email) ->from($from) ->to($to) ->subject('[SAM] SMTP 연결 테스트') ->text('이 메일은 SAM 시스템의 SMTP 연결 테스트입니다. 정상적으로 수신되었다면 설정이 올바릅니다.'); $transport->send($email); return true; } catch (\Exception $e) { return false; } } private function sendTestMailViaLaravel(array $config, string $to, string $from): bool { try { config(['mail.mailers.smtp_test' => $config]); config(['mail.mailers.smtp_test.transport' => 'smtp']); \Illuminate\Support\Facades\Mail::mailer('smtp_test') ->raw('이 메일은 SAM 시스템의 SMTP 연결 테스트입니다. 정상적으로 수신되었다면 설정이 올바릅니다.', function ($message) use ($to, $from) { $message->to($to) ->from($from, 'SAM 시스템') ->subject('[SAM] SMTP 연결 테스트'); }); return true; } catch (\Exception $e) { return false; } } private function parseTransportError(\Symfony\Component\Mailer\Exception\TransportExceptionInterface $e, int $responseTimeMs): array { $message = $e->getMessage(); // 에러 패턴 매칭 if (str_contains($message, 'Connection refused') || str_contains($message, 'Connection timed out')) { return [ 'success' => false, 'message' => 'SMTP 서버에 접속할 수 없습니다 — 호스트/포트를 확인하세요', 'response_time_ms' => $responseTimeMs, 'server_banner' => null, 'error_code' => 'CONN_REFUSED', ]; } if (str_contains($message, 'SSL') || str_contains($message, 'TLS') || str_contains($message, 'handshake')) { return [ 'success' => false, 'message' => '암호화 연결 실패 — 암호화 방식(TLS/SSL)을 확인하세요', 'response_time_ms' => $responseTimeMs, 'server_banner' => null, 'error_code' => 'TLS_FAILED', ]; } if (str_contains($message, 'Authentication') || str_contains($message, '535') || str_contains($message, 'credentials')) { return [ 'success' => false, 'message' => '인증 실패 — 사용자명/비밀번호(앱 비밀번호)를 확인하세요', 'response_time_ms' => $responseTimeMs, 'server_banner' => null, 'error_code' => 'AUTH_FAILED', ]; } if (str_contains($message, 'timed out') || str_contains($message, 'Timeout')) { return [ 'success' => false, 'message' => '연결 시간 초과 — 잠시 후 다시 시도하세요', 'response_time_ms' => $responseTimeMs, 'server_banner' => null, 'error_code' => 'TIMEOUT', ]; } return [ 'success' => false, 'message' => '연결 실패: '.$message, 'response_time_ms' => $responseTimeMs, 'server_banner' => null, 'error_code' => 'UNKNOWN', ]; } private function parseError(\Exception $e, int $responseTimeMs): array { return $this->parseTransportError( new \Symfony\Component\Mailer\Exception\TransportException($e->getMessage(), 0, $e), $responseTimeMs ); } /** * 에러 코드별 트러블슈팅 메시지 */ public static function getTroubleshoot(string $errorCode, ?string $preset = null): string { return match ($errorCode) { 'CONN_REFUSED' => '호스트 주소와 포트 번호가 정확한지 확인하세요. 방화벽이 해당 포트를 차단하고 있을 수 있습니다.', 'TLS_FAILED' => 'TLS와 SSL을 바꿔서 시도하세요. 포트 587은 보통 TLS, 포트 465는 SSL을 사용합니다.', 'AUTH_FAILED' => match ($preset) { 'gmail' => 'Gmail은 앱 비밀번호가 필요합니다. Google 계정 > 보안 > 2단계 인증 활성화 후 앱 비밀번호를 생성하세요.', 'naver' => '네이버 메일 설정에서 SMTP 사용을 활성화하고, 앱 비밀번호를 생성하세요.', 'daum' => '카카오 계정 > 보안 > 앱 비밀번호를 생성하세요.', default => '사용자명과 비밀번호를 확인하세요. 일반 비밀번호가 아닌 앱 비밀번호가 필요할 수 있습니다.', }, 'SMTP_DISABLED' => '메일 서비스 설정에서 SMTP 사용을 활성화하세요.', 'TIMEOUT' => '네트워크 상태를 확인하고 잠시 후 다시 시도하세요.', default => '설정을 다시 확인하고 재시도하세요.', }; } }