SMTP 메일이 전송되지 않고 연결이 실패하지만 openssl은 작동합니다

안녕하세요! 이 문제가 이미 명확한 해결책이 있는 것이라면 죄송합니다. 정말로 여기저기 찾아봤는데 제 문제에 대한 명확한 해결책을 찾지 못했습니다.

제가 직접 호스팅한 discord 인스턴스에서 몇 가지 설정을调整后 SMTP 설정을 올바르게 맞췄지만, 신규 사용자에게 이메일이 발송되지 않습니다 (초기 관리자 사용자에게도 발송되지 않았습니다. 결국 컨테이너 내부에서 rake 명령을 사용하여 관리자를 하나 생성했습니다).

처음에는 DNS 관련 문제 때문에 SMTP에 연결하지 못하는 줄 알았습니다. ./discourse-doctor를 실행하다가 결국 컨테이너 셸에 진입했을 때 다음과 같은 메시지가 반환되었기 때문입니다:

Testing sending to xxxx@gmail.com using smtp-relay.brevo.com:587, username:xxxxxxx@smtp-brevo.com with plain auth.
======================================== ERROR ========================================
Connection to port 587 failed.
====================================== SOLUTION =======================================
The most likely problem is that your server has outgoing SMTP traffic blocked.
If you are using a service like Mailgun or Sendgrid, try using port 2525.
=======================================================================================

그러나 SMTP 문제 해결 가이드에서 권장하는 openssl 명령을 실행했을 때 실제로 연결이 이루어졌을 뿐만 아니라, EHLO, AUTH LOGIN 및 기타 명령(지금까지 존재하는지 몰랐던 명령들, 헷 ^^')을 사용하여 컨테이너 내부에서 제 자신에게 테스트 이메일을 보내는 데 성공했습니다. 따라서 문제가 컨테이너가 SMTP 서버에 연결할 수 없는 것이 아니라고 생각합니다.

명확성을 위한 수정 사항
이것은 컨테이너 내부에서 수행했습니다: ./launcher enter container 명령을 사용하여 컨테이너에 로그인했습니다. 그 프롬프트에서 aforementioned 명령들을 실행했습니다.

도움이 될지 모르겠지만 제 SMTP 설정은 다음과 같습니다. 물론 로그인 정보는 편집했습니다.

  DISCOURSE_SMTP_ADDRESS: 'smtp-relay.brevo.com'
  DISCOURSE_SMTP_PORT: 587
  DISCOURSE_SMTP_USER_NAME: 'xxxxxxxx@smtp-brevo.com'
  DISCOURSE_SMTP_PASSWORD: 'xxxxxxxxxxxx'
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (optional, default true)
  #DISCOURSE_SMTP_DOMAIN: discourse.example.com    # (required by some providers)
  DISCOURSE_NOTIFICATION_EMAIL: 'noreply@mydomain.xyz'    # (address to send notifications from)
  #DISCOURSE_SMTP_OPENSSL_VERIFY_MODE: none

알림 이메일은 openssl 명령으로 테스트했던 것이고, 마지막 줄은 다른 게시물 어딘가에서 보고 추가한 것입니다. 하지만 주석 처리만 하고 시도해 본 적이 없는데, 그 게시물이 오래되었기 때문입니다.

어쨌든, 저는 정말로 막막한 상태입니다. 누군가 도움을 주셨으면 좋겠고, 제가 찾지 못한 이미 해결된 문제라면 정말 죄송합니다!

에러 메시지에 제안된 내용을 시도해보셔서 우연히 작동하는지 확인해 보실 수 있을까요?

안녕하세요! 이미 시도해 봤는데, 작동하지 않았습니다 :frowning:

openssl로 테스트 메일을 보낼 수는 있었지만, 포트 587을 통해서였습니다. 하지만 discourse 인터페이스를 통해(GUI의 테스트 메일 버튼과 rake tests:email[mail] 명령어 모두)는 포트 287과 2525를 통해서도 보내지 못했습니다.

또 다른 참고 사항으로, 전송되지 않은 메일에 대한 sidekiq 오류를 찾았습니다:

Jobs::HandledExceptionWrapper: Wrapped Net::OpenTimeout: execution expired

shared/standalone/log/rails/production.log에서 관련 로그 줄을 찾았습니다:

Started POST "/admin/email/test" for 192.168.0.206 at 2024-10-18 23:49:02 +0000
Processing by Admin::EmailController#test as */*
  Parameters: {"email_address"=>"jggalindez@gmail.com"}
Completed 422 Unprocessable Entity in 5201ms (Views: 0.4ms | ActiveRecord: 0.0ms | Allocations: 12487)

컨테이너 내부에서 포트 587에 연결할 수 있나요?

호스트에서는 포트 587에 연결할 수 있지만, 컨테이너 내부에서는 연결할 수 없는 것 같습니다. 이는 서버에서 네트워크 문제가 발생하고 있음을 의미합니다.

안녕하세요! 죄송합니다, 제가 좀 불분명하게 말씀드린 것 같습니다. 제 이해로는 컨테이너 내부에서 포트 587에 연결할 수 있었습니다. 구체적으로 다음과 같은 작업을 수행했습니다:

  • ./launcher enter containername 명령을 사용하여 컨테이너에 로그인했습니다.
  • 컨테이너 내부에서 openssl 명령을 실행했습니다.
  • 가짜 텔넷 프롬프트(실제로 이것이 무엇인지 정확히 잘 모르겠지만)에서 SMTP 서버에 인증을 수행했습니다(사용자 이름과 비밀번호를 base64로 변환하는 작업까지 포함). 그리고 이메일을 전송했습니다.

다만, 서버 내부에서 이메일을 보내는 것은 실제로 시도하지 않았습니다. 컨테이너 내부에서(제 이해로는) 시도했을 뿐이죠. 컨테이너 내부에서 가능했다면 서버 내부에서도 가능할 것이라고 생각했습니다.

드디어 해결했습니다. DNS 문제인 것 같습니다. (getentopenssl 명령을 사용할 때는 URL을 정상적으로 해석할 수 있었기 때문입니다.) 그래서 getent를 실행하여 SMTP 릴레이의 호스트 IP를 확인한 후, 컨테이너를 실행하면서 서버 주소를 해당 IP로 변경했습니다. 그랬더니 다른 오류가 발생했는데, 바로 이 스레드에 있는 오류였습니다. 거기에 제시된 해결책인 yaml 파일에 DISCOURSE_SMTP_OPENSSL_VERIFY_MODE: none 줄을 추가하는 것이 결국 문제를 해결해 주었습니다.

DNS 문제가 나중에 또 문제를 일으킬지는 모르겠네요. 안 그랬으면 좋겠어요 ㅋㅋ 하지만 도움 주셔서 감사합니다!

결국 컨테이너에서 네트워킹 문제가 발생하고 있는 것이 맞습니다. 다만, 이는 IP 연결 문제가 아니라 DNS에서 비롯된 것입니다.

컨테이너 내부에서 openssl s_client를 사용하여 호스트명에 연결할 수 있나요?

다음과 같이 실행할 수 있어야 합니다:

openssl s_client -connect smtp-relay.brevo.com:587 -starttls smtp

그리고 다음 결과가 나와야 합니다:

…
Verify return code: 0 (ok)
…

IP 주소로 연결하고 있고, 해당 IP 주소가 인증서에 포함되어 있지 않기 때문에 예상되는 결과입니다.

문제를 일으킬 것입니다.

네, 그렇게 생각해서 결국 설정 파일에 docker_args yaml 태그를 추가하고 dns 서버를 직접 지정했습니다.

docker_args 태그가 어디에 들어가는지 궁금하신 분들을 위해 (저도 찾아봐야 했거든요), app.yml 파일의 일부입니다:

*******Omitted lines above*********
## BE *VERY* CAREFUL WHEN EDITING!
## YAML FILES ARE SUPER SUPER SENSITIVE TO MISTAKES IN WHITESPACE OR ALIGNMENT!
## visit http://www.yamllint.com/ to validate this file as needed

docker_args: "--dns 1.1.1.1 --dns 8.8.4.4 --dns 8.8.8.8"

templates:
  - "templates/postgres.template.yml"
  - "templates/redis.template.yml"
  - "templates/web.template.yml"
  ## Uncomment the next line to enable the IPv6 listener
  #- "templates/web.ipv6.template.yml"
  - "templates/web.ratelimited.template.yml"
*******Omitted rest of file below*********