Configure direct-delivery incoming email for self-hosted sites with Mail-Receiver

안녕하세요! 가이드를 따라 설정을 마쳤는데, 잘 작동하고 있습니다! 다만, 이 설정들과는 무관할 것이라고 생각했던 외부 발송(outbound) 이메일에서 문제가 발생했습니다. mail-receiver를 활성화한 이후로, 모든 이메일 시도(모두 Retries 목록에 머물러 있는 상태)에 대해 Sidekiq가 다음 오류를 보고합니다:

Jobs::HandledExceptionWrapper: Wrapped OpenSSL::SSL::SSLError: SSL_read: unexpected eof while reading

검색 결과에 따르면 이것이 TLS와 관련이 있는 것 같습니다. .yml 파일에서 TLS 관련 줄을 주석 해제했는데, 다시 주석 처리해도 문제가 해결되지 않았습니다. 가이드에 있는 Postfix 충돌 해결 지침을 시도해 보았지만, 제 인스턴스에는 Postfix가 없는 것 같습니다? (가이드에 언급된 /etc/postfix 디렉토리가 제 인스턴스에 존재하지 않으며, postfix를 서비스로 인식하지도 않습니다.) 그리고 netstat 결과에 따르면 포트 25를 사용하는 것은 docker-proxy뿐입니다.

우리는 외부 SMTP 서비스로 Gmail을 사용하며, 사실 이 설정 이전에도 수신 POP3 폴링에 Gmail을 사용していました. Google을 가리키는 MX 레코드 여러 개를 삭제했지만, 가이드에서는 그렇게 하라고 했습니다.

아래는 특정 세부 사항을 삭제한 제 mail-receiver.yml 파일입니다:

## this is the incoming mail receiver container template
##
## After making changes to this file, you MUST rebuild
## /var/discourse/launcher rebuild mail-receiver
##
## 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

base_image: discourse/mail-receiver:release
update_pups: false

expose:
  - "25:25"   # SMTP

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8

  ## Where e-mail to your forum should be sent.  In general, it's perfectly fine
  ## to use the same domain as the forum itself here.
  MAIL_DOMAIN: discourse.[mydomain].org
# uncomment these (and the volume below!) to support TLS
  POSTCONF_smtpd_tls_key_file:  /letsencrypt/discourse.[mydomain].org/discourse.[mydomain].org.key
  POSTCONF_smtpd_tls_cert_file:  /letsencrypt/discourse.[mydomain].org/fullchain.cer
  POSTCONF_smtpd_tls_security_level: may


  ## The base URL for this Discourse instance.
  ## This will be whatever your Discourse site URL is. For example,
  ## https://discourse.example.com. If you're running a subfolder setup,
  ## be sure to account for that (ie https://example.com/forum).
DISCOURSE_BASE_URL: 'https://discourse.[mydomain].org'

  ## The master API key of your Discourse forum.  You can get this from
  ## the "API" tab of your admin panel.
  DISCOURSE_API_KEY: [myapikey]

  ## The username to use for processing incoming e-mail.  Unless you have
  ## renamed the `system` user, you should leave this as-is.
  DISCOURSE_API_USERNAME: system

volumes:
  - volume:
      host: /var/discourse/shared/mail-receiver/postfix-spool
      guest: /var/spool/postfix
# uncomment to support TLS
  - volume:
      host: /var/discourse/shared/standalone/letsencrypt
      guest: /letsencrypt

이메일 기술은 제 전문 분야가 아니므로, 조언을 감사히 받겠습니다. 설정을 할 때 멍청한 실수를 했다는 지적이라도 좋습니다. 감사합니다!

1개의 좋아요

예상하신 대로 목 수신기와는 무관합니다. 메일을 전송하는 호스트의 SSL 인증서가 손상되어 있습니다.

결국 여러 가지 문제를 겪은 끝에 원인을 찾았습니다. 문제는 우리가 Discourse 인스턴스를 호스팅하는 도메인과 MX 레코드가 설정된 도메인이 서로 달라서 생긴 것 같습니다. 이 혼란을 해소한 후에는 모든 것이 잘 맞춰졌습니다.

확실히 제 실수이지만, 가이드의 이 부분이 제 혼란을 조금이나마 부추겼습니다:

forum.example.com 항목이 반드시 동일할 필요는 없다는 점이 명확하지 않습니다. 제 경우에는 두 값이 서로 달라야 했습니다. 이 가이드를 사용하는 사람들은 이 정도는 이미 알고 있을 만큼 경험이 있을 수도 있지만, 저는 그렇지 않았습니다. 그래서 비슷한 문제를 겪을 수 있는 다른 분들을 위해 이 내용을 남겨둡니다. DNS에 대해 몰랐던 몇 가지 사실을 배울 수 있어서 좋은 학습 경험이었고, 지금은 모든 것이 잘 작동하고 있습니다. :slight_smile:

음, 내가 너무 성급하게 말했네요. 발신 이메일은 정상적으로 작동하고, 수신 답장도 정상적으로 작동하는 것 같지만, 카테고리 이메일 주소로 게시물을 작성하는 것은 조용히 실패하고 있습니다. 설정에서 주소를 그대로 복사해서 새 이메일에 붙여넣었기 때문에 오타가 없다는 것을 알고 있습니다.

mail-receiver 로그에는 기본적으로 세 가지 유형의 항목이 있습니다. 기존 게시물에 대한 이메일 답장이었던 성공적인 항목은 다음과 같습니다:

Sep 20 16:59:44 discourse-mail-receiver postfix/smtpd[277]: connect from server168-1.web-hosting.com[68.65.122.144]
Sep 20 16:59:45 discourse-mail-receiver postfix/smtpd[277]: NOQUEUE: reject: RCPT from server168-1.web-hosting.com[68.65.122.144]: 454 4.7.1 <[category]@discourse.[domain].org>: Relay access denied; from=<ryan@[redacted].com> to=<[category]@discourse.[domain].org> proto=ESMTP helo=<server168-1.web-hosting.com>
<22>Sep 20 16:59:45 policyd-spf[288]: : prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=[redacted]; helo=server168-1.web-hosting.com; envelope-from=ryan@[redacted].com; receiver=discourse.[domain].org Sep 20 16:59:45 discourse-mail-receiver postfix/cleanup[281]: 4CCED114200: message-id=<20240920165945.4CCED114200@discourse-mail-receiver.localdomain>
Sep 20 16:59:45 discourse-mail-receiver postfix/smtpd[277]: disconnect from server168-1.web-hosting.com[68.65.122.144] ehlo=1 starttls=0/1 mail=1 rcpt=0/1 data=0/1 quit=1 commands=3/6

그 외에는 (제가 오류라고 추정하는) 두 가지 유형의 항목이 있으며, 각각이 꽤 많이 반복됩니다. 첫 번째는 다음과 같습니다:

Sep 20 17:00:23 discourse-mail-receiver postfix/qmgr[124]: 5D162FC26D: from=<double-bounce@discourse-mail-receiver.localdomain>, size=960, nrcpt=1 (queue active)

그리고 다른 하나는 다음과 같습니다:

Sep 20 17:00:23 discourse-mail-receiver postfix/error[293]: 8DC3BFC141: to=<postmaster@discourse-mail-receiver.localdomain>, orig_to=<postmaster>, relay=none, delay=126622, delays=126622/0.05/0/0, dsn=4.4.3, status=deferred (delivery temporarily suspended: Host or domain name not found. Name service error for name=discourse-mail-receiver.localdomain type=MX: Host not found, try again)

그리고 제 mailq는 다음과 같이 생겼는데, 이 항목이 계속 반복됩니다:

3D07BFC23D      960 Fri Sep 20 06:42:23  double-bounce@discourse-mail-receiver.localdomain
(delivery temporarily suspended: Host or domain name not found. Name service error for name=discourse-mail-receiver.localdomain type=MX: Host not found, try again)
                                         postmaster@discourse-mail-receiver.localdomain

이 중 일부는 Discourse가 보내는 이메일이 어떤 이유로든 바운스되어 돌아오는 것들과 관련이 있는 것으로 보입니다. mail-receiver에는 이러한 바운스를 처리하는 기능이 있나요, 아니면 mailq에 영원히 남아 있게 되나요?

둘째, 왜 답장은 작동하지만 카테고리로 직접 이메일 게시를 하면 작동하지 않나요? 도움과 인내에 다시 한번 감사드립니다. :slight_smile:

이것은 게시물에 대한 성공적인 답장이 아니라, 카테고리 주소로 전송이 실패한 로그 항목처럼 보입니다.

100% 확신은 없지만, relay access denieddiscourse.[domain].orgmail-receiver.ymlMAIL_DOMAIN으로 사용된 도메인이 아닐 가능성이 높다는 것을 시사합니다. 아마도 답장 주소는 다른 방식으로 허용되고 있을 수 있습니다.

MAIL_DOMAIN에 사용되는 값은 최소한 postfix 설정 파일의 한 곳에 사용되므로, 변경하려면 컨테이너를 다시 빌드해야 할 가능성이 큽니다. MAIL_DOMAIN을 변경한 적이 있으며, 그렇게 했다면 그 후 ./launcher rebuild mail-receiver를 실행했나요?

2개의 좋아요

[이전 게시글을 작성하기 전에 실수로 Enter 키를 누른 점 사과드립니다]

아직도 이 문제로 고군분투하고 있습니다. 하지만 문제가 무엇일지 새로운 아이디어가 생겼습니다. 두 개의 도메인을 사용하고 있는데, [domain1]과 [domain2]라고 부르겠습니다. 제 Gmail SMTP 릴레이는 [domain1]에 호스팅되어 있습니다. 제 Discourse 인스턴스와 mail-receiver는 [domain2]에 호스팅되어 있습니다.

이메일이 [domain1]에서 발송될 때, Discourse의 reply-by-email-address 설정을 어떻게 해야 [domain2]의 답장 주소를 강제할 수 있을까요? 이렇게 하려고 하면 위에서 언급한 SSL EOF 오류가 발생합니다. DNS 인증 관련 트릭이나 제가 놓치고 있는 것이 있는 것 같습니다.

드디어 해결한 것 같습니다. '회신 주소’를 SMTP 릴레이와 다른 도메인으로 설정하려면 Google Workspace에서 몇 가지 설정을 완화해야 했습니다. 이제 양방향 모두 의도한 대로 정상 작동하는 것 같습니다.

1개의 좋아요

여기서 마지막 질문 하나만 드리겠습니다. 지금은 모든 것이 정상적으로 작동하지만, 여전히 mailq에 오래된 항목들이 남아 있습니다. 이는 아마도 잘못된 설정으로 생성된 이메일일 가능성이 높으며, 영원히 대기 상태에 머물러 있을 것입니다. 그냥 삭제하고 넘어가는 것이 낫습니다. 그러면 mailq를 어떻게 비울 수 있을까요?

조금 오래된 글이지만, SSL EOF 오류의 가장 흔한 원인은 OpenSSL 버전 간 충돌(v1.1.1f와 v3)입니다. 오래된 1.1.1f 버전을 업그레이드하는 것이 해결책이 될 것입니다. 그리고 나쁜 소식은 예를 들어 Ubuntu 20.x에서는 더 새로운 버전을 사용할 수 없다는 점으로, 따라서 Ubuntu 전체를 업그레이드해야 합니다.

1개의 좋아요

수시간을 보냈는데도 이 문제로 완전히 막혀 있습니다. 설정 파일 이름이 모두 소문자임에도 불구하고 이 Launcher 오류를 해결하지 못하고 있습니다.

“ERROR: Config name must not contain upper case characters, spaces or special characters. Correct config name and rerun ./launcher.”

다음 명령을 실행할 때 오류가 발생합니다:

./launcher rebuild mail-receiver

또는

./launcher bootstrap mail-receiver

또는

./launcher start mail-receiver

Launcher 코드베이스에서 이 부분을 확인할 수 있습니다.

아아아아아아 – 도와주세요!

위 링크된 게시글에서 로케일 관련해서 시도해 볼 수 있는 모든 것과, 다른 곳에서 찾을 수 있는 모든 방법을 시도해 보았습니다.

./launcher rebuild app___ 은 모두 정상적으로 작동합니다!

가능성이 있는 단서를 하나 찾았습니다. 이 문제는 제가 설정 파일 이름을 지을 때 실수로 CapsLock을 눌렀을 때(다만 2개의 문자만 대문자로 입력되었고) 즉시 CapsLock을 해제하고 저장하기 전에 그 2개의 문자를 다시 입력한 직후부터 발생하기 시작했습니다.

이 짧은 오타와 수정이 이런 문제를 일으켰다고는 상상하기 어렵지만, 어딘가 버퍼에 대문자 상태가 남아있는 것일 수도 있고, 아니면 ???일 수도 있습니다.

제 지식의 범위를 훨씬 벗어나는 내용이지만, 에러 메시지에 $config 변수가 출력되지 않는다는 점이 좀 의외입니다. :thinking:
디버깅에 분명히 도움이 될 텐데 말이죠.

1개의 좋아요

@Canapin 님, 감사합니다! - 제가 설정하려고 하는 것은 다음과 같습니다:

https://www.perplexity.ai/search/provide-the-code-lJcI4BrFQ2auuD42ehYFwA

명령줄의 모든 내용을 복사해서 붙여넣을 수 있을까요?

./launcher start mail-receiver 명령부터 오류 메시지까지, 그리고 정확한 .yml 파일 이름까지 포함해서요.

설정 파일 이름을 Mail-receiver.yml로 변경하면, ./launcher start Mail-receiver를 실행했을 때 다음과 같은 출력이 표시됩니다.

ERROR: Config name 'Mail-receiver' must not contain upper case characters, spaces or special characters. Correct config name and rerun ./launcher.

여기서 오류 메시지에 파일 이름이 포함되어 있습니다.

또한 ./launcher start aaa를 실행하면 해당 파일이 존재하지 않으므로 사용 가능한 파일 목록을 출력합니다. 파일은 폴더에서 가져오기 때문에 마법 같은 것은 없지만, 흥미로운 내용이 출력될 수도 있습니다 :person_shrugging:

ERROR: containers/aaa.yml does not exist or is not readable.

Available configs ( app, mail-receiver )

아, 정말 고마워요 – 해결해서 잘 작동하게 만들었어요.

결국 문제는 무엇이었나요? 다른 분들에게 도움이 될 수 있을 것 같습니다 :slight_smile:

1개의 좋아요

문제는 없었습니다. 단순히 도메인과 이메일 라우팅을 위해 서버의 다양한 구성 요소가 어떻게 상호작용하는지를 이해하는 데 학습 곡선이 필요했을 뿐입니다. 저는 이전에 포스트픽스(Postfix)에 대해 공부해 본 적이 없었습니다. 재미있었고 많은 것을 배웠습니다.

결국 도달한 해결책은 각 Discourse 인스턴스에 mail-receiver.yml(Docker 컨테이너)을 짝지어 사용하는 것입니다. 모든 인스턴스는 25번 포트를 공유하며, 포스트픽스의 transport 기능을 사용하여 라우팅을 처리합니다.

2개의 좋아요

전용 서버(Ubuntu 22.04 실행, Postfix 설치됨)에서는 메일 인박스 포스팅 기능이 활성화된 각 Discourse 인스턴스에 대응하는 별도의 mail-receiver.yml 파일을 사용합니다.

이 설정은 서버의 각 Discourse 인스턴스마다(일반적인 app 컨테이너와 함께) 해당 Discourse 인스턴스에 대한 이메일을 수신하고 처리하는 별도의 컨테이너를 생성합니다.

서버의 모든 Discourse 포럼에 대한 수신 이메일은 표준 포트 25를 통해 Postfix가 수신하며, 주요 Postfix 설정 파일은 "transport map"을 사용하여 이메일의 “To:” 주소에서 도메인 이름을 분석하여 각 이메일을 해당 Discourse 포럼으로 "릴레이"합니다.

따라서 이 주제의 지침 외에도 저는…

  1. 기존 postfix 설정 파일인 /etc/postfix/main.cf를 수정했습니다.

  2. 그런 다음, /etc/postfix/transport에 해당하는 postfix transport map 파일을 추가했습니다.

  1. 마지막으로, 각 포럼에 대한 이메일 컨테이너를 생성하기 위해 해당하는 파일을 추가했습니다:
    /var/discourse/containers/mail-receiver-domain1.yml
    /var/discourse/containers/mail-receiver-domain2.yml
    /var/discourse/containers/mail-receiver-domain3.yml
    /var/discourse/containers/mail-receiver-domain4.yml
    /var/discourse/containers/mail-receiver-domain5.yml

4개의 좋아요

mail-receiver.yml 파일에 DISCOURSE_MAIL_ENDPOINT 변수가 없으며, 변경해야 할 DISCOURSE_BASE_URL 변수도 있습니다.

2개의 좋아요

이메일을 JSON 형식으로 웹훅으로 전달하는 것을 지원하는 메일 포워딩 서비스를 사용하고 있습니다.

이것이 이메일의 직접 전달을 위한 옵션이 될 수 있을까요?

1개의 좋아요