반송된 이메일이 감지되지 않음

Discourse가 이메일 목록, 특히 반송된 이메일(bounced emails)을 정리하는 방법을 알아보고 있습니다. 사이트는 이메일을 보내기 위해 개인 SMTP 서버를 사용하고 있지만, 응답은 Discourse가 POP 접근을 위해 사용할 Gmail 주소로 돌아오도록 설정되어 있습니다.

그래서 Received 이메일 대시보드에서 반송된 이메일을 볼 수 있습니다.

그러나 Bounced 이메일 대시보드에는 아무것도 표시되지 않습니다.

Discourse 오류 로그를 확인해 보면, 반송된 이메일이 감지되고 있는 것을 볼 수 있습니다.

Email can not be processed: Email::Receiver::BouncedEmailError

Delivered-To: xxx.yyy@gmail.com
Received: by 2002:xxx:7022:911:xx:73:xxx:f96 with SMTP id xxx7csp1115046dlb;
Thu, 25 Jan 2024 12:03:33 -0800 (PST)
X-Google-Smtp-Source: AGHT+IEagzW8QOUgAyfOxU9wYaox/wuiL/wNqWhvftUB4uO/85r9H/55+FnfT6NrSTkLI5kfj+Vy
X-Received: by 2002:xxx:620a:4xxx:b0:xxxx:9265 with SMTP id br34-xxx8ba09265mr280168qkb.77.17062130xxx;
Thu, 25 Jan 2024 12:03:33 -0800 (PST)
Return-Path: <>
Received: from xxx.com (xxx.com. [207.xxx.xxx.xxx])
by mx.google.com with ESMTPS id bi4-xxx0b00783c84e9ef8si590747qkb.206.xxx.01.xx.12.03xxx
for xxx.yyy@gmail.com
(version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);
Thu, 25 Jan 2024 12:03:33 -0800 (PST)
Received-SPF: none (google.com: xxx.com does not designate permitted sender hosts) client-ip=207.xxx.xxx.xxx;
Authentication-Results: mx.google.com;
dkim=pass header.i=@xxx.co.nz header.s=alpha header.b=biFVvXep;
arc=fail (signature failed);
spf=none (google.com: xxx.com does not designate permitted sender hosts) smtp.helo=xxx.com;
dmarc=pass (p=NONE sp=REJECT dis=NONE) header.from=xxx.co.nz
Received: from xxx.co.nz (xxx.co.nz [210.xxx.xxx.5x])
by xxx.com (Postfix) with ESMTP id 4DD66xxx8E3
for xxx@zzz.com; Thu, 25 Jan 2024 20:03:28 +0000 (UTC)
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zzz.com;
s=dkim; t=1706213008;
h=from:from:reply-to:subject:subject:date:date:message-id:message-id:
to:to:cc:mime-version:mime-version:content-type:content-type:
dkim-signature;

따라서 질문은 다음과 같습니다.

  1. 왜 Discourse가 반송된 이메일을 반송으로 표시하지 않는 것이며, 이를 어떻게 수정할 수 있습니까?

Discourse는 reply_key를 사용하여 반송(bounce)을 발송된 이메일과 연결합니다. Discourse가 메일을 발송할 때, SMTP 봉투 발신자로 reply_by_email_address 값을 사용합니다.

반송이 올바른 발송 메일과 연결될 수 있도록 인스턴스에서 reply_by_email_address에 {reply_key}가 포함되어 있는지 확인해야 합니다.

예를 들어, 여기 meta에서는 incoming+%{reply_key}@meta.discoursemail.com으로 설정되어 있으며, 해당 주소로 설정된 모든 메일은 이 인스턴스로 전달됩니다.

답변해 주셔서 감사합니다. 불행히도 이메일 리레이 서버에서 + 주소를 인식하지 못하여, 이메일 응답에서 reply_key를 꺼야 했습니다. 다른 옵션이 있을까요?

사용자의 이메일 릴레이 서버는 중요하지 않으며, 메일박스가 위치한 최종 서버만 중요합니다. 이메일의 로컬파트(localpart)는 모든 중간 서버에 대해 불투명(opaque)합니다.

다음과 같이 Gmail이 아닌가요?


바운스(bounce)를 신뢰할 수 있게 감지하는 다른 메커니즘이 있는지 확실하지 않습니다.

정리하자면, 바운스된 이메일을 받는 대상 SMTP 도메인 서버는 + 주소 지정 방식을 인식하지 못합니다. 따라서 해당 서버는 To 필드 기준으로만 이메일을 Gmail 주소로 전달하며, 이 Gmail 주소는 Discourse가 POP를 통해 가져옵니다. 즉, To 필드에 reply_key가 포함되어 있으면, 해당 이메일은 Discourse가 사용하는 Gmail 계정으로 전달되지 않습니다.

따라서 이메일 주소에 reply_key를 넣을 수 없는데, 다른 위치에 넣을 수 있을까요? Discourse가 이를 파싱할 수 있는 주제(subject) 필드나 본문(body) 또는 다른 어디ś에 넣을 수 있을까요?

설정에서 실제로 사용 중인 내용을, 약간 익명화하더라도 적어주시면 매우 도움이 될 것입니다.

alternative_reply_by_email_addresses 설정을 살펴보는 것도 좋습니다.

그렇지 않은 것으로 보입니다.

가능한 경우, 귀하의 설정에 대해 다음과 같은 구성을 권장합니다:

  • reply_by_email_address를 inbound+%{reply_key}@forum.hostname으로 설정
  • forum.hostname의 이메일을 수신하고 이를 모두 the.gmail.account@gmail.com으로 전달하도록 메일 서버 구성

여기서 중간 메일 서버는 플러스 어드레싱을 이해할 필요가 없으며, 해당 도메인에 대한 모든 것을 전달하기만 하면 됩니다.

네, 물론입니다

이메일 파싱 설정:

이메일 발송 설정:

  • Discourse가 보내는 이메일은 discourse@xxx.com에서 discourse 전용으로 설정된 도메인 SMTP 서버를 통해 발송됩니다. (discourse 도메인 주소를 사용함)
  • 답장이 오거나 이메일이 바운스(bounce)될 경우, 해당 도메인 SMTP 서버는 이메일을 discourse.xxxx@gmail.com으로 전달합니다. 이 도메인 SMTP 서버는 + 주소 지정 방식을 인식하지 못하므로, 답장 이메일 주소에 reply_key를 포함하면 도메인 SMTP 서버에서 제거됩니다. 저는 개별/고유한 수신 이메일 주소에 대한 전달 규칙만 설정할 수 있습니다.
  • Discourse 포럼은 GMail을 통해 POP 프로토콜로 해당 전달된 답장/바운스 이메일에 접근하여 이를 파싱합니다.

이 정보가 도움이 될까요?

말씀하시는 내용을 이해합니다. 불행히도 SMTP 서버 규칙의 제한으로 인해 서브도메인에 대한 포워딩을 설정할 수 없으며, 고유한 To 이메일 ID에 대해서만 포워딩을 구성할 수 있습니다.

하지만 여기서 한 가지 확인 사항이 있습니다. 더스크(Discourse)의 작동 방식에 대해 불일치가 있는 것 같습니다:

  1. 사용자가 이메일 게시글에 답장할 때, 답장은 올바르게 수신됩니다. 어디에도 {reply_key}가 명시적으로 구성되지 않았음에도 답장은 완벽하게 작동하는 것 같습니다(위 스크린샷 참조).
  2. 그러나 이메일이 반송(bounced)되면, 더스크는 이를 Received로 분류하지 Bounced로 분류하지 않습니다.
  3. 에러 로그는 더스크 내에서 무언가가 반송된 이메일임을 인식하고 있음을 보여줍니다(제 첫 번째 게시물의 에러 로그 참조). 따라서 더스크 내에서 무언가가 반송된 이메일임을 인식하고 있다면, 왜 Received가 아니라 Bounced로 표시되지 않는 것일까요?

그렇다면 사용자가 게시글에 답장할 때는 더스크가 올바르게 처리하지만, 반송된 이메일은 왜 그렇지 않은 것일까요(또한 에러 로그와 반송 이메일 대시보드 사이에도 불일치가 있는 것으로 보입니다). 구성에서 제가 놓치고 있는 부분이 있을까요?

저도 discourse에서 이메일 주소로 답변 설정을 discourse.xxx+%{reply_to}@gmail.com으로 변경해 보았지만, 이메일이 전달될 때 Gmail은 yyy.com 도메인(discourse SMTP 도메인)이 Gmail 도메인을 스푸핑하려는 것으로 판단하여 스팸으로 분류합니다. 발신자 도메인과 다른 답변 도메인을 설정하는 것이 DMARC 및 SPF 실패를 유발하는 것으로 보입니다.

ARC-Authentication-Results: i=1; mx.google.com;
       spf=softfail (google.com: domain of transitioning discussion.xxx+verp-b9c40db917ca04993dd3433cc9748518@gmail.com does not designate y.y.y.y as permitted sender) smtp.mailfrom=discussion.xxx+verp-b9c40db917ca04993dd3433cc9748518@gmail.com;
       dmarc=fail (p=NONE sp=NONE dis=NONE) header.from=yyy.com
Return-Path: <discussion.xxx+verp-b9c40db917ca04993dd3433cc9748518@gmail.com>

find related posts with key 옵션을 끄셨네요 (경고 메시지를 읽으셨기를 바랍니다). 이로 인해 Discourse는 답글이 어떤 주제/게시글을 참조해야 하는지를 결정하기 위해 in-reply-to 메일 헤더를 사용하고 있습니다.

바운스된 이메일의 경우 이렇게 할 수 없습니다. Discourse는 반드시 바운스된 특정 메시지를 알아야 하며, 이 정보는 한 곳에서만 보장됩니다. 바로 To: 주소입니다(원본 메시지의 envelope-from 주소에서 유래합니다).

이것이 작동하려면, Discourse가 메시지를 보낼 때 해당 메시지가 온 주소로 답장을 받아야 합니다. Discourse는 이를 위해 To: 헤더를 확인합니다(envelope-to가 아닙니다).

실제로 gmail 도메인을 스푸핑하고 있습니다.

gmail 주소에서 메일을 보내려면 해당 메일을 구글의 서버를 통해 보내야 합니다. 하지만 구글은 이를 원하지 않습니다.

yyy.com에 대해 DKIM을 설정하지 않은 것으로 보입니다. 설정해 두시는 것이 좋습니다. 이를 올바르게 설정하면 DMARC 검사를 통과할 것입니다.

구성되어 있으며, Discourse가 yyy.com SMTP 서버를 통해 “보낸” 이메일은 관리 콘솔의 “테스트 이메일 보내기” 페이지에서 확인했을 때 SPF, DKIM, DMARC를 모두 문제없이 통과합니다.

이 문제는 reply_by_email_address를 yyy.com 주소 대신 Gmail 주소로 설정할 때 발생합니다. 발신 서버를 yyy.com으로 유지하면서 reply_by_email_address를 Gmail 주소로 설정했을 때 DMARC가 실패하지 않도록 이 설정을 위해 할 수 있는 방법이 있을까요?

“명백한” 위치에서 필요한 정보를 찾을 수 없는 경우, 바운스된 이메일의 나머지 콘텐츠/첨부 파일에서 해당 정보를 추출하도록 파싱할 수 없나요? (또는 위장 공격에 대한 필요한 경고와 함께 그렇게 할 수 있는 옵션을 설정에 제공하는 것도 좋습니다.)

이 상황에서 reply_by_email_address가 envelope-from 주소로 사용되기 때문에 DMARC 정렬이 실패합니다.

반송 시 무결성이 보장되는 것은 거의 오직 주소뿐입니다.

아마도 제목은 그럴 수 있지만, 그 위치에 이러한 정보를 넣는 것은 실용적이지 않습니다.

일부 시스템에서는 원래 메시지를 첨부 파일로 포함하는 것을 확인했습니다… 첨부 파일이 존재하는 경우, 더 많은 정보를 얻기 위해 반송된 이메일의 첨부 파일을 확인하는 것이 이론적으로 가능할 수 있습니다.

제가 이해한 바로는, Discourse(yyy.com)가 전송하는 envelope의 reply-to 필드에 reply_by_email_address가 설정되어야 합니다. 따라서 사용자가 회신할 때 원래의(yyy.com) 주소가 아니라 reply-to 이메일(gmail.com)에 답장하게 됩니다. 즉, 이메일 응답 envelope에서 from 주소는 사용자의 이메일 주소가 되고, to는 gmail.com 주소가 되어야 합니다.

왜 reply_by_email_address가 from 주소로 사용될까요?

reply_by_email_address는 from 주소로 사용되는 것이 아니라, 바운스(bounce)가 정상적으로 작동하도록 하기 위해 구체적으로 envelope-from으로 사용됩니다.

각 주소가 어떻게 사용되는지 보여주는 이미지가 있습니다. 주소 자체는 저희 호스팅 환경에 특화되어 있지만, 예시로 충분할 것입니다.

notification_email: notifications@hs1.discoursemail.com
reply_by_email_address: incoming+%{reply_key}@hs1.discoursemail.com

알림(notification):

답장 가능한 메시지(replyable message):

감사합니다. 정말 큰 도움이 됩니다.

즉, reply_by_email_address는 from 헤더에 사용되어 반송(bounce)된 경우 해당 이메일 주소로 되돌아오도록 하는 데 사용됩니다. 또한 이메일로 회신이 활성화된 경우, 동일한 이메일 주소가 reply-to 헤더에도 설정됩니다.

따라서 제 이해가 맞다면, Discourse에 reply-to 헤더를 위한 별도의 설정(reply_to_email)을 추가할 수 있다면 DMARC 실패 문제를 해결할 수 있을 것입니다. 발송 시 from에는 reply_by_email_address에서 가져온 yyy.com 도메인을 사용하고, reply-to에는 새로운 reply_to_email 설정에서 가져온 gmail.com을 사용하는 방식입니다. 이렇게 하면 이메일이 반송되어도 여전히 reply_by_email_address로 되돌아오지만, 사용자가 회신하면 reply_to_email로 보내지게 됩니다.

그것은 SMTP envelope-from이지, From 헤더가 아닙니다. From 헤더는 반송 처리에 사용되지 않습니다.

즉, ②가 아니라 ①입니다:

DMARC를 통과하려면, SPF(envelope-from과 전송 IP를 조합하여 검증) 또는 DKIM(메시지의 From 및 checksums 필드를 검증) 중 하나가 정렬되어야 합니다.

이 작업의 핵심은 사용자가 답장하는 “예쁜” reply-to 주소를 갖는 것인 것 같습니다?

이런 것을 원하시나요?

envelope-from: outgoing+12309847801923840923502389423@yyy.com
…
From: notifications@yyy.com
To: user@contoso.com
Reply-to: my_sweet_forum+12309847801923840923502389423@gmail.com

반송이 정상적으로 작동하지 않을 것이므로, envelope-from은 반드시 이렇게 가져야 합니다.

네, 맞습니다. envelope-from과 reply-to를 다르게 설정하는 것이 아이디어입니다.

envelope-from 도메인과 발송 IP가 일치하므로 SPF는 통과해야 하지만, 동시에 답장은 GMail로 가서 응답을 처리하게 됩니다. 그리고 이메일이 바운스(bounce)되면 원래 도메인 서버로 돌아가게 되며, 이 서버는 다시 바운스를 GMail 수신함으로 전달할 수 있습니다.

실제로는 다음과 같이 보일 것입니다:

envelope-from: outgoing@yyy.com
…
From: notifications@yyy.com
To: user@contoso.com
Reply-to: my_sweet_forum+12309847801923840923502389423@gmail.com

제 설정에서는 수신 SMTP가 VERP를 지원하지 않기 때문에(즉, 바운스된 메일에 VERP 주소가 포함되지 않기 때문에) outgoing에 VERP가 없습니다. 그래서 VERP를 지원하는 GMail로 reply-to를 보내는 것입니다. 이렇게 하면 현재처럼 DMARC 실패가 발생하지 않아야 합니다.