| CMS/프레임워크 | Rhymix 2.1 |
|---|---|
| 개발 언어 | PHP 7.4 |
daum smtp 이메일 발송을 이용 중입니다.
회원가입 이메일 인증과 글, 댓글 이메일 알림을 이용중인데 최근에 메일 발송 내역을 보면 대부분 정상인데 간헐적으로 아래와 같은 에러 유형이 보입니다.
에러 메시지:
Connection to ssl://smtp.daum.net:465 Timed Out
호출 위치:
/****/****/www/common/framework/Mail.php line 618
ai에게 간단한 방법으로 증상이 개선되는지 확인 해 볼 수 있는 방법을 요청했는데 아래와 같은 답변을 받았습니다.
코어를 건드리는 부분이긴 하지만 아래 답변을 적용해도 무방할지 문의드립니다.
Daum 서버 일시 과부하 또는 네트워크 순간 불안정이 원인이므로, 재시도 로직 추가만으로도 상당 부분 해결되는 경우가 많습니다.
common/framework/Mail.php
// ❌ 기존 (send() 메서드 내부)
try
{
$this->sent = $this->driver->send($this) ? true : false;
}
catch(\Exception $e)
{
$this->errors[] = $e->getMessage();
$this->sent = false;
}
// ✅ 변경
$maxRetry = 3;
for ($i = 0; $i < $maxRetry; $i++)
{
try
{
$this->sent = $this->driver->send($this) ? true : false;
if ($this->sent) break; // 성공 시 즉시 종료
}
catch(\Exception $e)
{
$this->errors[] = $e->getMessage();
$this->sent = false;
if ($i < $maxRetry - 1) sleep(2); // 마지막 시도가 아니면 2초 대기
}
}
딱 이 블록만 교체하시면 됩니다. trigger 호출이나 나머지 로직은 그대로 유지되므로 안전합니다.
댓글 2
1. 최대 3회, 각각 2초간 대기하도록 하셨는데, 타임아웃 상황이라면 거기에 또 5~10초씩 추가되니, 최악의 경우 메일을 발송할 때마다 30초 이상 지연될 수 있습니다. 메일 알림을 많이 발송하는 사이트라면 글쓰기가 무한 지연되는 부작용이 일어날 수도 있다는 뜻이지요. 그냥 메일 한 통 안 가고 말았을 일시적인 과부하나 네트워크 불안정을 해결하려다가, 서비스 자체를 마비시키는 더 큰 과부하나 불안정을 일으킬 수 있으니 조심하세요.
2. 하나의 메일을 여러 수신자에게 보내는 경우, 메일 서비스에 따라서는 일부 수신자만 실패하더라도 실패로 취급할 수 있습니다. 이 때 모든 수신자에게 재발송하게 되면 누군가는 메일을 중복으로 받게 될지도 모릅니다. 물론 위의 시나리오처럼 메일 서버에 아예 접속하지 못했다면 어느 누구에게도 발송하지 못했을 테니 중복 문제는 걱정하지 않아도 되겠지요. 그러나 재시도할 필요가 없거나, 재시도해서는 안 되는 오류 상황(유효하지 않은 수신자 주소, 아이디/비번 오류 등)일 수도 있으니, 무조건 재시도하기보다 어떤 오류인지 구분할 필요가 있겠습니다.
3. 최신 라이믹스의 비동기 기능을 사용하면 메일 발송을 백그라운드에서 처리하니, 3번씩 재시도하더라도 타임아웃 문제로부터 좀더 자유로울 수 있을 것 같습니다.
답변감사합니다.
비동기 기능을 적용중인데요. 답변내용을 잘 이해했는지 모르겠지만 타임아웃인 상황에서만 재시도( 다른 에러상황은 재시도 제외 - 이메일 주소오류, 수신함 용량초과...) 를 시도하는 아래 코드를 적용하면 좀 더 적합한 방법이 될까요?
$maxRetry = 3;
for ($i = 0; $i < $maxRetry; $i++)
{
try
{
$this->sent = $this->driver->send($this) ? true : false;
if ($this->sent) break;
}
catch(\Exception $e)
{
$this->errors[] = $e->getMessage();
$this->sent = false;
// 타임아웃 관련 에러일 때만 재시도
$isTimeout = stripos($e->getMessage(), 'timed out') !== false
|| stripos($e->getMessage(), 'timeout') !== false
|| stripos($e->getMessage(), 'Connection') !== false;
if (!$isTimeout || $i >= $maxRetry - 1) break; // 타임아웃 아니면 즉시 중단
sleep(2);
}
}
타임아웃일 때만 재시도하고, 452/550 같은 에러는 즉시 포기하니 안전합니다.