복원 다음 날, 티켓이 쏟아진다
Veeam Backup for Microsoft 365로 사서함 복원을 막 끝냈습니다. 작업은 잘 됐고, 데이터도 있고, 폴더도 멀쩡합니다. 그런데 월요일 아침, 사용자가 메시지를 보냅니다. "제 이메일이 전부 오늘 날짜로 돼 있어요. 아무것도 못 찾겠어요."
이메일이 사라진 게 아닙니다. 다 있어요. 하지만 표시되는 날짜가 원래 발송일이 아니라 복원 작업이 완료된 시각으로 나옵니다. 2021년 1월에 받은 이메일이 어젯밤 23시 47분에 수신된 것처럼 보이는 거죠. 대화 스레드는 엉키고, 시간순 정렬은 완전히 무너집니다.
이 문제는 Veeam Backup for Microsoft 365, Datto SaaS Protection, Synology Active Backup for Microsoft 365, AvePoint Cloud Backup 등에서 공통적으로 나타납니다. 각 도구마다 방식은 조금씩 다르지만, 결과는 똑같습니다.
기술적으로 무슨 일이 벌어지는가
잘못된 날짜가 어디서 오는지 이해하려면, 이 도구들이 Exchange Online이나 Google Workspace 사서함에 이메일을 다시 주입하는 방식을 봐야 합니다.
백업 도구가 메시지를 복원할 때, 로컬 디스크에서 파일을 옮기듯 단순히 "제자리에 갖다 놓는" 건 불가능합니다. 도구는 IMAP을 통해서든, 제공업체의 API를 통해서든(Microsoft 쪽은 EWS나 Microsoft Graph, Google 쪽은 Gmail API) 메일함에 메시지의 새 사본을 기록합니다. 그리고 그 사본과 함께, 메시지가 어떤 날짜를 가지는지도 메일함에 전달해야 합니다.
그리고 바로 여기서 문제가 시작됩니다. (복원된 이메일의 원시 헤더를 직접 열어 본 적이 있다면, 실제 내용에 도달하기 전에 Received: 헤더가 스무 줄 넘게 쭉 이어지는 걸 보셨을 겁니다.)
IMAP APPEND 명령과 Received: 헤더
IMAP 프로토콜에는 APPEND라는 명령이 있습니다. 사서함에 메시지를 삽입하는 명령이에요. 복원 도구가 정확히 이 방식을 씁니다. 저장된 메시지를 꺼내서 IMAP APPEND로 대상 사서함에 주입하는 거죠.
이 명령을 통해 도구는 메시지와 함께 날짜를 전달할 수 있습니다. 도구가 이메일의 원래 날짜를 전달하면, 메일함은 그 날짜를 그대로 유지합니다. Microsoft 365, Outlook.com, Gmail 모두 마찬가지입니다. 아무 날짜도 전달하지 않거나 복원 시점의 날짜를 전달하면, 메일함은 이메일을 복원한 날짜로 분류합니다. 그리고 메시지를 다시 기록하는 일부 방식은 맨 위에 한 줄을 더 추가합니다. 복사한 날에 찍힌 Received: 헤더입니다. Gmail의 임포트 API가 바로 그렇게 동작합니다.
새로 추가되는 줄은 대략 이런 형태입니다.
Received: by gmailapi.google.com
with HTTPREST; Mon, 14 Apr 2025 23:47:12 +0000
결과적으로, 메시지 내부의 원본 Date: 헤더("3 Jan 2021 09:15:00" 같은)는 그대로 남아 있습니다. 하지만 복원 시각이 찍힌 새 Received: 헤더가 맨 위에 덧붙여진 상태가 됩니다.
Outlook과 Gmail이 날짜를 읽는 방식
Outlook이나 Gmail 웹 인터페이스 같은 이메일 클라이언트는 메시지 목록에 표시할 날짜를 결정할 때 항상 Date: 헤더를 참조하지 않습니다. 많은 클라이언트가 IMAP 프로토콜의 INTERNALDATE(메시지가 사서함에 추가된 시각)나 가장 최근의 Received: 헤더를 사용합니다.
특히 Outlook for Windows는 2023년 말 업데이트 이후 이 점에 더욱 민감해졌습니다. 헤더 체인 맨 위에 최근 Received: 헤더가 있으면, Outlook은 그걸 표시 날짜로 사용합니다. 원본 Date: 헤더는 이메일 속성을 직접 열어야 확인할 수 있는 세부 정보로 밀려납니다.
최종 사용자 입장에서는 메시지 목록 전체가 복원 작업을 한 그날 밤 날짜로 가득 찬 걸 보게 됩니다. 3년치 이메일 히스토리가 하룻밤으로 압축된 것처럼요.
마이그레이션 날짜 오류와의 차이
IMAP 마이그레이션 후 날짜가 잘못 표시되는 문제와 구분이 필요합니다. 마이그레이션의 경우, 도구가 서버 A에서 서버 B로 이메일을 이동하고, 각 이메일이 날짜를 유지하는지는 도구가 기록할 때 서버 B에 무엇을 전달하는지에 달려 있습니다. 메커니즘은 같지만 맥락이 다릅니다.
여기서 다루는 건 백업에서의 복원입니다. 이메일은 조직을 떠난 적이 없고, 어딘가(Azure Blob Storage, AWS S3, Datto 어플라이언스...)에 안전하게 보관되다가 다시 주입된 것입니다. 사용자 입장에서는 더더욱 당황스럽습니다. 수입된 이메일이 아니라 "자신의" 이메일이 돌아온 거라고 생각하니까요.
하지만 기술적으로는 동일한 메커니즘입니다. 원래 날짜를 전달하지 않는 재주입은 같은 아티팩트를 만들어 냅니다. 수정 방법도 같은 논리를 따릅니다.
각 도구별 INTERNALDATE 처리 방식
모든 도구가 정확히 같은 방식으로 동작하지는 않습니다. 이 부분이 꽤 흥미롭습니다.
Veeam Backup for Microsoft 365
Veeam은 Exchange Online 복원 시 EWS(Exchange Web Services) API를 사용합니다. EWS는 DateTimeReceived 필드로 메시지 날짜를 지정할 수 있지만, 이 값이 항상 IMAP 레벨의 INTERNALDATE에 반영되지는 않습니다. 결과적으로 Outlook의 정렬 날짜가 원본 날짜와 맞지 않을 수 있으며, 특히 원본 사서함이 아닌 다른 사서함으로 복원하는 세분화 복원(granular restore) 시나리오에서 두드러집니다.
Datto SaaS Protection
Datto는 설정에 따라 Microsoft Graph API나 IMAP으로 복원합니다. 두 경우 모두, 메일함에 표시되는 날짜는 복원이 각 메시지의 원래 날짜를 전달하는지에 따라 달라집니다. Datto로 고객 사서함을 관리하는 MSP들은 이 문제를 꽤 자주 만납니다. 랜섬웨어 사고 이후 수백 개의 사서함을 긴급 복원하다가 날짜가 전부 잘못됐다는 걸 뒤늦게 알게 되는 건, 최악의 타이밍이죠.
AvePoint와 Synology Active Backup
AvePoint Cloud Backup과 Synology Active Backup for Microsoft 365도 유사한 메커니즘을 따릅니다. AvePoint는 자사 지식 기반에서 이 동작을 문서화했습니다. 메시지가 수신 날짜로 표시되는 날짜와 함께 복원된다는 내용이지만, 네이티브 수정 방법은 제공하지 않습니다. Synology Active Backup도 동일한 문제가 있으며, 복원 인터페이스가 "메시지 날짜"와 "복원 날짜"를 명확히 구분하지 않아서 혼란을 더합니다.
반가운 소식: 원본 날짜는 여전히 거기 있다
상황을 복구할 수 있는 이유가 있습니다. 메시지의 원본 Date: 헤더가 수정되지 않았기 때문입니다. 복원된 각 이메일 내부에 원본 날짜가 그대로, 온전히 남아 있습니다. 복원 과정에서 메일함에 기록된 날짜가 바뀌었고, 경우에 따라 위에 Received: 줄이 추가되었을 뿐, 메시지 내용 자체는 건드리지 않은 거죠.
이건 MIME 형식(RFC 2822)의 특성 때문입니다. 메시지의 내부 구조는 불변합니다. Received: 헤더들이 층층이 쌓이더라도, 원래 정보는 그 아래에 그대로 남아 있습니다.
즉, 날짜 정보를 잃은 게 아닙니다. 재주입 아티팩트에 가려져 있을 뿐입니다.
복원을 다시 하는 게 해결책이 아닌 이유
가장 먼저 떠오르는 아이디어: 복원된 이메일을 삭제하고 다시 복원하면 이번엔 날짜가 맞게 들어오지 않을까. 안타깝게도 좋은 생각이 아닙니다. 이유가 몇 가지 있습니다.
우선, 복원 도구는 두 번째 시도에서도 다르게 동작하지 않습니다. 같은 도구, 같은 설정이라면, 이메일은 원래 날짜 없이 같은 방식으로 다시 기록됩니다. 결과는 똑같습니다.
게다가, 운영 중인 사서함에 복원을 다시 실행하는 건 시간, 대역폭, 그리고 리스크를 수반합니다. 사서함 50개에 각각 20,000개의 메시지가 있다면, API를 수 시간 동안 점유하고 Microsoft나 Google 쪽에서 속도 제한이 걸릴 수도 있는 작업입니다. 배치 작업 중 새벽 2시에 뜨는 그 유명한 429 Too Many Requests 오류처럼요.
복원은 잘 됐습니다. 데이터는 거기 있어요. 수정해야 할 건 복원 자체가 아니라 날짜 아티팩트입니다.
직접 수정할 때의 구체적인 위험
문제를 이해하는 것과 80,000개의 이메일을 하나도 잃지 않고 수정하는 것은 별개의 문제입니다.
IMAP 메시지를 순회하며 날짜를 수정하는 Python 스크립트는 만들 수 있을 것처럼 보입니다. 테스트 이메일 50개에서는 잘 작동할 거예요. 하지만 운영 환경은 다릅니다. 엣지 케이스들이 쌓입니다. S/MIME 서명된 이메일(헤더 수정 시 암호화 서명이 무효화됨), PGP 암호화 메시지, 비표준 MIME 경계를 가진 멀티파트 구조, RFC 2047로 인코딩된 헤더(비ASCII 문자), 스크립트 메모리를 초과하는 40MB 첨부파일. 그리고 복원이 부분적으로 재실행된 경우처럼 Received: 헤더가 여러 개 쌓인 이메일들은 더 정교한 탐지 로직이 필요합니다.
정확히 말하면, 진짜 위험은 스크립트가 멈추는 것이 아닙니다. 오류 없이 돌아가면서 손상된 메시지를 만들어 내는 스크립트가 더 무섭습니다. 끊긴 스레드, 중복 메시지, 분리된 첨부파일. 사용자가 중요한 이메일을 찾으려 할 때까지 몇 주 동안 모를 수도 있습니다.
수정 후 각 이메일이 실제로 온전한지 어떻게 검증하실 건가요? 자체 제작 스크립트는 대부분 이걸 하지 않습니다.
Redate.io가 다르게 하는 것
Redate.io는 각 이메일의 헤더 체인을 분석해서 재주입 아티팩트를 식별합니다. Veeam 복원이든, BitTitan 마이그레이션이든, 수동 임포트든 상관없습니다. 독자적인 교정 엔진은 어떤 도구가 문제를 일으켰는지 알 필요가 없습니다. 표시된 날짜가 원래 날짜와 일치하지 않는 이메일을 찾아내므로, 이름이 알려지지 않은 도구라도 걸러낼 수 있습니다.
수정 전에, Redate.io는 전체 사서함을 스캔하고 리포트를 제공합니다. 영향받은 이메일 수, 잘못된 날짜, 탐지된 원본 날짜가 모두 나옵니다. 이 스캔은 무료입니다. 조치를 결정하기 전에 문제의 전체 범위를 먼저 확인할 수 있습니다.
교정 후 각 이메일은 개별적으로 검증됩니다. 원본은 사서함 안의 눈에 보이는 백업 폴더에 그대로 남아 있으며, 직접 삭제하기 전까지 계속 보관됩니다.
Redate.io는 각 사용자가 자신의 Microsoft 계정이나 Google 계정으로 로그인하면 그 사서함을 바로 엽니다. 별도 포털이나 애플리케이션 등록 없이, 사서함 안에서 직접 교정이 이루어집니다. 내보내기나 재임포트 없이요.
동시에 여러 고객 사서함을 관리하는 MSP라면, MSP 전용 페이지를 참고하세요. Redate.io는 단일 인터페이스에서 여러 사서함을 병렬로 처리할 수 있습니다.
같은 아티팩트를 만드는 다른 시나리오들
백업 도구에서의 복원만이 유일한 사례는 아닙니다. 같은 날짜 아티팩트가 다음 상황에서도 나타납니다.
- Exchange IMAP 임포트 (Exchange Online으로 아카이브 사서함 재주입)
- Exchange Online으로의 마이그레이션 (목적지 측에서 IMAP을 사용하는 도구)
- PST 내보내기 후 재임포트를 통한 세분화 복원 (PST 임포트 관련 글 참고)
- 장애 후 재구성된 공유 사서함 (공유 사서함 날짜 수정 참고)
이 모든 경우에서 기저 메커니즘은 동일합니다. 원래 날짜를 전달하지 않는 재주입(때로는 위에 새 Received: 헤더가 붙는)과, 그 새 날짜를 기준 날짜로 보여주는 이메일 클라이언트입니다.
이메일은 있습니다. 원본 날짜도 각 메시지 안에 보존되어 있어요. Redate.io에서 무료 스캔을 시작하면 사서함에서 영향받은 이메일이 정확히 몇 개인지 확인하고, 교정 진행 여부를 그다음에 결정할 수 있습니다.