1. 한글 Encoding

문자 집합 (Charset)

한글의 7비트 인코딩이 처음 표준화된 것은 RFC 1557에서 ISO-2022-KR이 제졍되면서였습니다. 하지만, ESMTP에서 8비트 전송을 명기하고, 7비트 인코딩이 사장되어 감에 따라서, 표준안에서는 ISO-2022-KR 대신에 KSC5601 charset을 사용하는 것을 제안하고 있습니다.

하지만, 이미 실용적으로 EUC-KR (Extecded Unix Code for Korean)이 널리 사용되고 있고, KSC5601임을 표시하는 방식도 엄청나게 다양해서 다 처리하기 힘들 정도입니다. 실제로 Outlook Express와 같은 MUA에서도 이미 EUC-KR이 가장 안정적으로 지원되는 charset이고, 여타 다른 시스템에서도 가장 널리 사용되고 있는 de facto standard는 euc-kr이 아닌가 싶습니다.

호환 가능한 charset, Content-Transfer-Encoding

다음은 charset마다 사용 가능한 Encoding 방식을 나타냅니다.

ISO-2022-KR / 7bit
EUC-KR / 8bit, base64, quoted-printable


실제로는 이렇게 되어야 한다는 보장은 없습니다. 어차피 Encoding과 charset은 별개의 것이니까요.

7비트 Encoding은 점점 사라지고 있지만, 아직 사용되는 시스템을 위해서 Decoding은 지원하는 것이 좋겠다는 권장 사항이 있습니다.

헤더의 Encoding에서도 한글에 대해서는 대부분 "B" Encoding이 권장됩니다. 특별히 ASCII 문자가 많은 경우가 아니라면, "Q" Encoding을 사용할 이유는 별로 없습니다.



2. CRLF의 처리

RFC822를 보면, 가장 처음에 나오는 내용 중의 하나가...

모든 Line은 CRLF의 조합으로 끝난다...


입니다. 하지만, 이는 실제로 잘 안 지켜지는 내용 중의 하나입니다.

가장 큰 문제는 Platform마다 text/plain의 형식이 조금씩 다른 것 때문이라고 생각됩니다.
각 Platform마다 나타나는 차이첨을 살펴보면,

   Unix/Linux: 모든 Line은 LF로 끝난다. (간단하군요 ^^;)
   DOS/Window: 마지막 Line을 제외한 모든 Line은 CRLF로 끝난다.
   Macintosh: 모든 Line은 CR로 끝난다.

여기서 파생되는 문제점은 두 가지입니다. 전적으로 MIME Encoder의 문제지만, Decoder도 이에 대한 대비를 할 수 있어야 합니다.

   각 Line이 반드시 CRLF로 끝난다는 보장이 없다.
   마지막 Line에 CRLF가 누락된 경우가 상당히 많다.

두번째 경우가 더 큰 문제를 야기할 수 있습니다. 특히 Multipart로 구성된 메시지인 경우에 Epilogue를 인식할 수 없는 경우가 생기는 것이지요.

여담이지만, Outlook Express를 보면서 상당히 놀랄 수밖에 없었던 것이, 여러 가지 경우를 테스트하면서 온갖 종류의 규격에 맞지 않는 어떤 메일이 들어온다고 하더라도, Decode하지 못하는 경우를 거의 발견하지 못했다는 것입니다. (여태 딱 한 번 봤습니다. 이 경우도 왜 못하는지를 잘 이해할 수 없더군요.)
. HTML에 대한 Content-Transfer-Encoding

기본적으로 8bit Encoding 즉, Encoding을 하지 않거나, Base64 혹은 Quoted-Printable로 Encoding하는 것이 권장됩니다. 그다지 특별한 내용은 아니지요?

Outlook Express의 경우를 보면, 대부분의 경우에는 base64로 HTML 문서를 Encoding합니다만, 특별히 설정하지 않는 경우에 있어서는 multipart/alternative로 구성할 때, text/plain 쪽은 base64로, text/html 쪽은 quoted-printable로 구성하는 것을 볼 수 있습니다. 아무래도 앞에서도 언급한 quoted-printable의 장점 때문이겠지요?



2. HTML에 대한 Content-Type

charset 지정을 위해서 문서 안에 아래와 같은 META 태그를 사용하는 것을 권장하고 있습니다. 물론, 이 META 태그가 모든 Browser에서 다 먹히는 것은 아닙니다.

<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=euc-kr">



3. Image의 처리

아래의 링크와 IMG 태그를 보시죠...

<a href="../example.html"> ... </a>
<img src="image/icon.gif">

두 경우 모두 그대로 전달된다면, MUA가 HTML 메시지를 지원한다고 하더라도 제대로 디스플레이될 수 없습니다. 대부분의 문서에서, URL이 들어가는 부분에 상대 주소를 사용하고 있기 때문이죠. HTML 메시지를 처리할 때, 생길 수 있는 문제는 바로 이 부분이죠.

어떤 식으로 HTML을 구성해야 이런 문제를 해결할 수 있을까요?

절대 URL로 Image 접근이 가능한 경우

이런 경우는 어렵지 않게 문제를 해결할 수 있습니다. 이런 경우에 사용할 수 있는 방법은 두 가지입니다.

   URL을 모두 절대 경로로 바꾸는 겁니다. 그러면 MUA에서 알아서 Image를 보여줄 수 있습니다. 다만 모든 URL이 나타나는 곳의 주소를 조심스럽게 변경해야 한다는 번거로움이 있겠네요.
   또 하나의 방법은 BASE 태그를 쓰는 것이지요. HTML 문서의 대부분의 URL이 하나의 Base URL에 포함되는 경우에 유용합니다. 위의 방법과 마찬가지로 이 방법도 상당히 많이 사용됩니다.

이런 경우에 HTML 메시지는 두 가지로 구성할 있습니다.

   Top Level Content-Type이 text/html인 메시지
   text/plain과 text/html로 구성된 multipart/alternative 메시지

절대 URL로 Image 접근이 불가능한 경우

이런 경우는 사용자의 컴퓨터에서 직접 HTML을 편집하고, 로컬 컴퓨터에 있는 이미지를 문서에 포함시켰을 때에 발생하게 됩니다.

여기서는 아까도 잠시 언급한 multipart/related 를 사용합니다.

각 Part는 아래와 같이 구성합니다.

   첫번째 본문 파트는 text/html 혹은 multipart/alternative로 구성한다.
   이후의 모든 Embedded Image를 각각의 Body Part로 구성한다.
   각 Part에 Content-ID를 부여하여 HTML 본문 중의 모든 URL과 아래와 같은 방식으로 연결한다.

<img src="cid:<Content-ID>">


예를 하나 보시기 바랍니다.

(전략...)
Content-Type: multipart/related;
    boundary="----=_NextPart_000_0008_01BF162B.976B0000";
    type="multipart/alternative"
(중략...)

This is a multi-part message in MIME format.

------=_NextPart_000_0008_01BF162B.976B0000
Content-Type: multipart/alternative;
    boundary="----=_NextPart_001_0009_01BF162B.976B0000"

------=_NextPart_001_0009_01BF162B.976B0000
Content-Type: text/plain; charset="ks_c_5601-1987"
Content-Transfer-Encoding: 8bit

(텍스트 메시지)

------=_NextPart_001_0009_01BF162B.976B0000
Content-Type: text/html; charset="ks_c_5601-1987"
Content-Transfer-Encoding: 8bit

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
<META content="text/html; charset=ks_c_5601-1987" http-equiv=Content-Type>
</HEAD>

<BODY bgColor=#ffffff>

...
<IMG src="cid:000501bf15e0$276dfb40$865566d2@bawi.org">

...

</BODY>
</HTML>

------=_NextPart_001_0009_01BF162B.976B0000--

------=_NextPart_000_0008_01BF162B.976B0000
Content-Type: image/jpeg; name="m001.jpg"
Content-Transfer-Encoding: base64
Content-ID: <000501bf15e0$276dfb40$865566d2@bawi.org>

Image 내용...

------=_NextPart_000_0008_01BF162B.976B0000--

   Content-Type이 "multipart/related"로 되어 있습니다. 여기에 boundary가 붙고, type이라는 parameter를 사용하고 있습니다. type이 "multipart/alternative"로 되어 있는데, 이는 뒤에 "text/plain"과 "text/html"이 같이 있다는 것이 되겠네요.

   HTML 메시지의 중간에 IMG 태그가 있고, src에 지정된 URL이 Content-ID임을 알 수 있습니다. 그리고 뒤의 한 본문 파트에 같은 Content-ID가 있는데, 이 부분이 이후에 이 HTML 메시지가 디스플레이될 때, 어떻게든 처리가 되는 겁니다.


이런 식으로 하면, 복잡하지만 HTML 메시지와 거기에 포함된 이미지 등을 함께 보내는 것이 가능합니다.

 

출처 : http://www.iwiz.pe.kr/bbs/zboard.php?id ··· Bno%3D39

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2009/01/14 02:29 2009/01/14 02:29

 

. 인터넷 텍스트 메시지의 구조

인터넷 텍스트 메시지는 다음과 같이 구성됩니다.

메시지 = 헤더 + 본문
헤더와/본문의 구분 : NULL 라인

   메시지는는 한 개 이상의 텍스트 라인으로 구성합니다.
   각 라인은 Carriage Return(CR)과 Line Feed(LF)의 조합(CRLF)으로 끝나게 되어 있으며, 헤더의 경우를 제외하면 각 라인의 최대 길이는 최대 76자로 되어 있습니다.
   헤더와 본문을 구분하기 위해서 사이에 NULL 라인을 넣게 되어 있네요. NULL 라인 이라 함은 CRLF로만 구성된 라인을 말합니다.

헤더에서 보면 가끔 한 줄이 76자를 넘는 필드도 있습니다. 그래도 한도 끝도 없이 길어질 수는 없고 대략 한 줄의 길이를 최대 512자 정도(SMTP에서의 제한)로 생각하면, 큰 문제 없습니다.

위에서 나타낸 구조에 따르자면 헤더가 끝나는 시점은 NULL 라인이 나타나는 시점이겠죠. 즉, NULL 라인이 처음 나오기 전까지가 헤더라고 볼 수 있습니다. 그런데, 잘못 구성된 메일 시스템에서 헤더 중간에 NULL 라인을 들어간 것들이 가끔 있습니다.

 

2. 헤더 필드의 구성

헤더에 들어가는 각 필드는,

<필드 이름>: <필드 내용>CRLF
의 형식으로 구성됩니다.

여기서 <필드 이름>은 대소문자를 구분하지 않습니다. 그러니까, From/FROM/from 이런 것들은 모두 똑같다는 겁니다.
경우에 따라서 읽는 사람이 좀 더 편하게 읽게 하기 위해, 또는 다른 제약 때문에, 필드 내용을 여러 줄에 쓰는 경우가 있습니다. 이 경우에는 연속된 필드라는 것을 표시하기 위해서 줄의 맨 앞에 연속된 공백문자(LWSP Char: Linear White Space Character)를 넣도록 되어 있습니다. LWSP에 해당되는 문자로는 SPACE, TAB 등을 들 수 있겠죠. (Backspace는 제외됩니다)

예를 들면, 아래와 같은 네 가지 헤더 필드는 모두 똑같습니다. CRLF도 LWSP 문자의 일부로 인식하는거죠. 여러 줄의 필드 내용이 합쳐질(unfolding) 때에는 LWSP 문자들은 하나의 SPACE 문자로 처리합니다. 백스페이스 같은 문자는 공백 문자로 취급하지도 않을 뿐더러 좀 위험하겠죠.

To: "Joe & J. Harvey" , JJV @ BBN
To: "Joe & J. Harvey" ,
       JJV@BBN
To: "Joe & J. Harvey"
       , JJV
   @BBN
To: "Joe &
   J. Harvey" , JJV @ BBN

그래서 헤더를 처리할 때에는 첫 글자가 SPACE 혹은 TAB이면 전줄의 헤더에 이어지는 줄이라는 것을 알 수가 있죠. 보통 대부분의 시스템에서는 간편하게 TAB 하나만 넣는 경우가 많지만, 경우에 따라서는 여러 개의 SPACE가 들어가는 경우도 있습니다. 따라서 LWSP에 대한 처리는 필수라고 할 수 있겠지요.



3. 괄호의 사용

헤더의 필드 내용에서는 괄호도 용도가 정해져 있습니다.

(, ) : 괄호는 주석을 넣기 위해서 사용합니다.
:, ; : 콜론과 세미콜론은 주소 지정시에 그룹을 표시하기 위해서 사용합니다.
<, > : 양쪽 꺽쇠는 주소 지정이나 Routing 경로를 표시할 때, 사용합니다.
[, ] : 대괄호는 IP Address를 직접 지정하기 위해서 사용합니다.


다음에는 각 헤더 필드에 대한 내용을 보도록 하죠...

 

1. 헤더 필드의 순서

헤더 필드의 순서는 꼭 이리해야 한다...고 규정짓고 있지는 않지만, 이 순서가 권장되고 있습니다.
RFC에서 Recommended 라고 표시되는 부분인데, 이런 부분은 반드시 강제하는 것은 아니지만, 여러 가지 이유로 볼 때, 큰 문제 없으면 따르도록 되어 있는 부분들이고, 실제로 대부분의 관련된 프로그램에서 그렇게 하고 있습니다.

Return-Path
Received
Date
From
Subject
Sender
To
cc
그외...

대부분의 MTA(Mail Transfer Agent)에서 이 순서를 거의 지키고 있습니다.
Microsoft Exchange Server의 경우에, 원하는 대로 헤더 필드가 들어오지 않는 경우에는 Decoding에 문제가 좀 생기기도 한다는군요.



2. 각종 헤더 필드

날짜/시간 관련 헤더 필드

   "Date" 헤더 필드

문법
"Date: " date-time
date-time := [ day "," ] date time
day := "Mon" / "Tue" / "wed" / "Thu" / "Fri" / "Sat" / "Sun"
date := 1or2Digit month 2Digit
month := "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun"
           / "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
time := hour zone
hour := 2Digit ":" 2Digit [":" 2Digit]
zone := "UT" / "GMT" ; Universal Time
         / "EST" / "EDT" ; Eastern
         / "CST" / "CDT" ; Central
         / "MST" / "MDT" ; Mountain
         / "PST" / "PDT" ; Pacific
         / 1Alpha ; Military (Z, A, M, N, Y...)
         / ("+" / "-") 4Digit ; Local Difference


Mon, 11 Oct 1999 16:17:24 +0900

문법이 굉장히 복잡하지요? 보기만 복잡하지 예를 보면 아주 간단합니다. 맨 앞의 요일은 있을 수도 있고, 없을 수도 있습니다. 그 뒤에는 날짜와 시간, 그리고 지역 시간대를 표시합니다. 이 필드는 보통 MTA가 알아서 넣어 주죠.


경로 추적을 위한 헤더 필드

여기에는 Return-Path, Received가 있습니다.

Return-Path: route-addr
Received: ...
...

   "Return-Path" 헤더 필드
메시지 전송이 실패했을 경우, 메시지가 되돌아갈 메일박스(id@host 형식)를 지정합니다. 메일 박스, 주소를 지정하는 방식은 워낙 다양하므로, 뒤에 보도록 하죠. 이 필드도 보통 MTA가 설정해주도록 되어 있습니다.

   "Received" 헤더 필드
실제 메시지 소스를 보면 이 헤더 필드는 여러 개가 들어 있는 것을 알 수 있습니다. 이 필드는 메일이 어떤 중간 경로를 통해서 전달되었는지를 추적하기 위해서 MTA가 자동적으로 추가합니다. 보통 MTA를 설정할 때, 여기에 몇 개 이상의 "Received" 헤더가 있으면 메일이 루프를 돌고 있거나 전달될 수 없는 것으로 처리하는 경우가 많죠.


발신자에 대한 정보를 담고 있는 헤더 필드

여기에는 From, Sender, Reply-To가 있습니다.

From: mailbox
Sender: address
Reply-To: address

   "From" 헤더 필드
From은 편지 봉투의 보낸 사람 이름 쓰는 곳에 쓰는 내용입니다. 즉, 메시지를 보낸 사람의 (명목상?) 메일 박스를 표시합니다.

   "Sender" 헤더 필드
Sender는 있어도 되고 없어도 됩니다. 있는 경우에는 From과 의미가 약간 중복되죠. 우리가 직접 편지를 쓰더라도 다른 사람에게 우체국에 가져가서 보내줄 것을 부탁할 수 있듯이, 이 필드는 실제 메시지를 보낸 사람을 표시하기 위해서 사용합니다. 그럴 경우가 아니라면 필요없죠.

   "Reply-To" 헤더 필드
Reply-To는 메시지의 답장을 받을 사람의 주소입니다. 보통의 경우는 From의 주소와 같은 주소를 사용합니다. 경우에 따라서 다르게 설정할 수도 있겠죠.

이 Field가 설정되어 있는 경우에는 답장을 보낼 때, From을 참조하지 않습니다.
이 Field가 설정되어 있지 않은 경우에는 From를 참조하여 답장을 보내게 됩니다.


수신자에 대한 헤더 필드

여기에는 To, Cc, Bcc가 있습니다.

To: address
cc: address
bcc: address

   "To" 헤더 필드
메시지를 받을 사람(들)의 주소를 지정합니다. 여러 사람을 지정할 수도 있고, 그룹을 만들 수도 있습니다. 이 Field에 지정되는 수신자는 "주수신자"라고 부릅니다.

   "cc" Field
역시 메시지를 받을 사람(들)을 지정할 수 있습니다. 여기에 지정되는 수신자는 "부수신자"라고 부릅니다. 보통 "참조"라고 표시하죠.

   "bcc" Field
"부부수신자"라고 해야 하나요? 보통 "숨은 참조"라고 표시합니다.


기타 헤더 필드

Subject: text
Messeage-ID: msg-id
In-Reply-To: msg-id

   "Subject" 헤더 필드
말 그대로 메시지 제목을 적는 필드입니다. 이 필드가 Optional하다는 것은, 이 필드가 없어도 제목은 메일의 송수신에는 지장이 없다는 뜻이 되겠네요.

   "Message-ID" 헤더 필드
말 그대로 메시지의 ID죠. 보통 현재 시각 (1970년 1월 1일 자정부터 지금 시각까지를 초단위로 계산한 것), MTA의 IP주소 등을 조합해서 만듭니다. 어떤 곳에 쓰인다는 언급은 없습니다. 메일의 열람 확인에 쓰이기도 합니다.


확장 / 사용자 정의 헤더 필드

보통 "X-"로 시작하는 헤더 필드는 RFC에서 표준으로 규정하고 있는 필드가 아니라, 확장된 헤더 필드를 의미합니다. 그 중에서 많이 쓰이는 것으로는 "X-Priority", "X-Mailer" 등이 있습니다.



3. 주소 지정 방식

일반적인 도메인 이름을 지정할 때는 별 제약이 없지만, 직접 IP Address를 지정할 때에는 대괄호([, ])를 사용합니다.

[10.0.3.19]


아래는 실제로 From, To 등에 많이 사용하는 주소 지정 방법들입니다.

   메일 박스를 직접 지정합니다. 가장 간단한 방법이죠.

Neuman@BBN-TENEXA

   앞에 메일 박스를 수식하는 문자를 함께 사용하는 방법입니다. 이 방법을 가장 많이 사용하죠.

Alfred Neuman

   따옴표 사용

"George, Ted"

   주석도 사용가능합니다. 하지만 처리하기 복잡해지겠죠.

Wilt. (the Stilt) Chamberlain@NBA.US
(Wilt.Chamberlain@NBA.US와 동일합니다)

   그룹 지정이 가능합니다.

Gourments: Pompous Person ,
    Childs@WGBH.Boston, Galloping Gourmet@
   ANT.Down-Under (Australian National Television),
    Cheapie@Discount-Liqours;
   Cruisers: Port@portugal, Jones@EA;
    Another@Somewhere.SomeOrg


 

 

출처 :  http://www.iwiz.pe.kr/bbs/zboard.php?id ··· Bno%3D37

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2009/01/14 02:27 2009/01/14 02:27

 

 

 . MIME

MIME(Multipurpose Internet Message Extension)은 말 그대로 Internet Message를 통해서 여러 가지 내용을 보낼 수 있도록 확장한 규격입니다.

한글같은 2바이트 Non-ASCII 문자가 여러 메일 서버를 무사히 통과하기 위해서는 7비트 ASCII 문자로 일단 변환되어야 합니다. 물론, 요즘의 대부분의 메일 시스템은 보통 8비트의 Non-ASCII 문자들도 손상시키지 않고 통과시키만 (8bit clean이라 하죠...), 그렇지 않은 경우도 아직 꽤 많습니다. 때문에, 그냥 8비트인 상태로 보내면, 메시지가 올바로 간다고 보장할 수 없게 됩니다. 게다가 단순한 텍스트 뿐만이 아니라, 요즘에는 바이너리 파일도 메일에 첨부하는 경우가 많죠?

그런 것들을 위해서 MIME에서는 Message Body에 있는 내용의 형태, Encoding 방식, 각 부분의 연관 관계 등을 지정할 수 있는 규약을 정하고 있습니다.



2. MIME Header

MIME 형태를 지정하기 위해서 RFC822에서 정의된 Header Field 외에 몇 가지 Header Field가 새로 정의되었습니다. 이 Header들은 message의 Top Level Header 혹은 Message Body Part의 Header에 들어갑니다.

MIME-Version Header Field
Content-Type Header Field
Content-Transfer-Encoding Header Field
Content-Disposition Header Field
Content-ID Header Field
Content-Description Header Field


MIME-Version Header Field는 Message의 주 Header에 있게 됩니다.
Content-Type, Content-Transfer-Encoding Header Field는 Top Level Header에 있을 수도 있고, Body Part의 Header에 있을 수도 있습니다.
Content-Disposition Header Field는 Top Level Header에 쓰일 수도 있지만, 대부분의 경우에는 Body Part의 Header에 있게 됩니다.


1. MIME-Version 헤더 필드

MIME 규약에 따르는 Message는 이 Header를 반드시 가지고 있어야만 합니다. 필수라고 RFC에서는 강조하고 있지만, 이 Header FIeld를 가지고 처리할 수 있는 건 아무 것도 없습니다. 그래서 실제로는 이 Header Field가 빠진 메시지도 상당히 많습니다.

MIME-Version: 1.0

지금 현재 MIME 버전은 현재까지는 무조건 1.0 입니다. 이 헤더를 가지고 있으면, 이후의 모든 내용은 MIME의 규격을 준수한다는 것을 의미하게 됩니다. 물론 실제로 보장되지는 않습니다.
EBNF Form으로 구성하면 아래와 같이 됩니다.

version := "MIME-Version" ":" 1Digit "." 1Digit

아래의 세 가지 예 모두 동일하며, 문제 없는 형식입니다.

MIME-Version: 1.0 (prodeced by MetaSend Vx.x)
MIME-Version: (prodeced by MetaSend Vx.x) 1.0
MIME-Version: 1.(prodeced by MetaSend Vx.x)0



2. Content-Type 헤더 필드

메시지 본문 혹은 본문의 각 부분의 내용의 종류를 지정하는 헤더 필드입니다. 보통 MIME Type이라고 부르는 것들은 바로 이걸 말하죠. 이 헤더 필드의 문법은 아래와 같습니다.

content := "Content-Type" ":" type "/" subtype *(";" parameter)

"Content-Type:" 이라는 헤더 이름 다음에, "타입/서브타입"과 같은 형태로 지정합니다.
그리고 여기에 parameter를 붙이고 싶으면 세미콜론으로 구분하면서 계속 적어나가면 됩니다.

타입은 크게 두 가지로 나뉩니다.
첫번째는 Discrete-Type인데, 이 것은 그 자체로 어떤 의미를 가지고 있는 Content-Type이 됩니다. 예를 들어, Text라든지, Image 같은 것들이 여기에 해당됩니다.
각각의 Type은 여러 가지 Subtype을 가질 수 있습니다. 예를 들어서, Text의 경우에는, 일반 ASCII 텍스트를 나타내는, text/plain, text/html 등의 Subtype을 가집니다.
Discrete-Type에 해당되는 것들은 아래와 같습니다.

"text" / "image" / "audio" / "video" / "application" / extension-token

두번째는 Composite-Type입니다. 이것은 Discrete-Type 혹은 Composite-Type의 개체 여러 개가 복합되어 만들어진 타입입니다. 이런... 재귀적인 설명이 되어 버렸군요. Composite-Type은 일단은 두 가지 입니다. 그 외에 확장된 타입을 둘 수 있다고 되어 있습니다. 이 중에서 MIME 규약이 점점 커지면서 다양한 서브 타입이 생겨나고 있는 것은 multipart 타입입니다.

"message" / "multipart"

Content-Type 헤더 필드가 없는 메시지도 많습니다. 이런 경우에는 어떻게 처리해야 할까요?
이 헤더가 없는 메시지는 MIME 규약이 생기기 전에 만들어진 메시지로 취급하면 됩니다. 즉, 단순한 ASCII 텍스트로만 이루어진 메시지로 처리하는 거죠...
아래가 Content-Type 헤더 필드가 없는 경우의 기본 Content-Type이 됩니다.

Content-Type: text/plain; charset=us-ascii

각 Content-Type에 대한 좀 더 자세한 내용은 다음에 설명하도록 하겠습니다.



3. Content-Transfer-Encoding 헤더 필드

이 헤더 필드는 메시지의 본문이나 본문의 각 부분이 어떤 방식으로 Encoding되었는지를 나타냅니다. 이 헤더 필드의 문법은 아래와 같습니다.

encoding := "Content-Transfer-Encoding" ":" mechanism

mechanism에는 다섯 가지가 있습니다.

"7bit" / "8bit" / "binary" / "quoted-printable" / "base64"

7bit, 8bit, binary를 먼저 보자면... 이 경우는 Encoding을 하지 않았다는 얘깁니다.

   7bit는 원래 ASCII 문자만 있다는 것을 의미하고,
   8bit는 8비트 문자들도 그래도 들어 있다는 것을 의미하고,
   binary는 8bit와 같은데, 한 줄의 길이의 제한이 없다는 것을 의미합니다. (안 쓰인다고 보면 됩니다).

물론, 한글을 7비트로 Encoding한 경우는 물론 Decoding이 필요합니다.
이 방식은 사라지고 있고, 요즘에는 한글은 base64로 Encoding하는 경우가 절대 다수이니까요.

그 다음에 특정한 알고리즘을 필요로 하는 두 개의 Encoding 방식이 있습니다.
Quoted-Printable하고 base64 Encoding이죠.

   Base64 Encoding은 간단히 말해서 3바이트의 데이타를 4바이트에 저장하는 겁니다. 24비트를 6비트씩 4개로 나누어서 따로 저장하고 각 바이트의 위쪽 두 비트를 0으로 하니까 무조건 ASCII 문자라는게 보장이 되는 거죠.
따라서 8비트 중에서 6비트만 사용하므로, 인코딩 결과로 나온 메시지는 모두 64가지의 Octet만을 가질 수 있게 됩니다. 그래서 Base64라고 부릅니다.
이 64개의 Octet는 ASCII와 같은 코드셋에도 독립적으로 설계되었습니다.
이 Encoding 방식의 장점이라고 하면, 원래의 데이타가 Encoding 후에 크기가 얼마가 될지 거의 정확하게 예측할 수 있다는 거죠. 약 33%정도가 늘어나죠. 또 다른 인코딩 방식에 비해 공간을 덜 차지하기 때문에, 효율적이라고 할 수 있습니다. 반면, Encoding을 하고 나면 원래 내용이 뭔지 도저히 알아볼 수 없다는 단점이 있죠.

   Quoted-Printable 방식은 ASCII 문자가 아닌 놈들만 "=XX" (X : 0...9, A...F)와 같은 모양으로 Encoding 하는 방식을 말합니다. 따라서 7Bit ASCII로 표현할 수 없는 문자는 한 바이트가 3바이트로 늘어나게 됩니다. 따라서, 이 방식은 크기가 최대 3배로 늘어날 수 있으니까 효율성 면에서는 거의 최악이라고 할 수 있습니다.

이 Encoding 방식은 영어 문화권에서 보면 나쁜 Encoding이 아닐 수 있습니다. 영어 문화권에서 만들어지는 텍스트는, 대부분의 문자가 7비트 ASCII 문자로 되어 있고, 그렇지 않은 문자가 훨씬 적습니다. 따라서, 이 방식으로 Encoding을 하면, 대부분의 글자가 Encoding이 되지 않고 일부분만이 Encoding이 됩니다.
그러니까, 일단 오히려 효율적일 수도 있고, 다양한 Decoding을 수행하지 못하는 MUA에서 메일을 보더라도, 대략적으로 내용을 파악할 수 있다는 거죠. 반면 한글 같이 거의가 Non-ASCII 문자인 Message나 바이너리 파일 같은 경우는 이 방식으로 Encoding 해봤자 좋은 점이 없습니다. 괜히 메모리나 디스크, 네트워크만 더 잡아먹을 뿐이지요.

정리하자면 Quoted-Printable Encoding은 Decoding이 안 되더라도 내용을 대략적으로 알아볼 수 있지만, 효율이 안 좋고, base64 Encoding은 효율이 좋지만, Decoding하기 전까지는 내용을 전혀 못 알아볼 수 없다는 겁니다.

그래서, 대부분의 ASCII 문자가 많은 텍스트나 HTML의 경우에는 Quoted-Printable로 Encoding 하는 경우가 많고, 한글이나 바이너리 파일은 거의 무조건 base64로 Encoding합니다.
이것은 그냥 그런 경우가 많이 있다는 것이고, 실제로 각 Body Part의 Encoding의 MUA 맘대로 (혹은 사용자의 선택으로) 하게 되겠죠.


4. Content-Disposition 헤더 필드

이 헤더 필드는 각각의 본문의 부분이 화면에 바로 보여야 하는지, 아니면 첨부된 파일로 보여서, 사용자가 따로 처리해야 하는지를 명시하기 위해서 사용됩니다. 문법은 아래와 같습니다.

disposition := "Content-Disposition" ":" disposition-type *(";" disposition-param)

disposition-type이 붙고 parameter가 붙을 수 있습니다.
disposition-type에는 두 가지가 있을 수 있습니다.

"inline" / "attachment"

inline은 사용자가 메시지를 보려고 할 때, 무조건 화면에 나타나야 한다는 걸 말하고, attachment는 메시지의 주 본문과는 별도로 처리될 수 있다는 걸 표시합니다. 물론 요즘 Windows용 MUA같은 경우에는 첨부된 그림 파일 같은 건 바로 화면에 보여주죠? attachment는 반드시 따로 처리해야 하는게 아니라, 반드시 화면에 바로 나타낼 필요는 없다는 걸 알려주는 겁니다.

parameter는 아래와 같은 형식으로 만들 수 있습니다. attachment같은 경우에는 "filename" parameter를 지정하는 것이 일반적입니다.

disposition-param := "filename" "=" value
    / "creation-date" "=" quoted-date-time
    / "modification-date" "=" quoted-date-time
    / "read-date" "=" quoted-date-time
    / "size" "=" 1*Digit

이 헤더가 필요한 이유는 Content-Type만을 보고 이 메시지 덩어리가 inline인지, attachment 인지 판단하기 힘든 경우가 많기 때문입니다.
예를 들어서, 어떤 사람이 텍스트로 메일을 열심히 쓴 다음에 참고할 만한 텍스트 파일을 첨부해서 메일로 보냈다고 합시다. 그러면 이 사람이 작성한 주 본문의 Content-Type은 text/plain이겠죠? 이 사람이 첨부한 파일의 Content-Type도 text/plain이겠죠?
그러면 메일을 받았을 때, 어느 부분이 진짜 주 본문인지 판단하기 힘들죠. 보통은 주 본문을 앞에 두니까, 별 상관없다고 할 수 있지만, 받은 메시지만 보고 판단할 방법은 없다는 겁니다.
어쨌든 보통의 MUA에서는 주 본문에 해당되는 부분에는 이 헤더를 굳이 설정하지 않고, attach에 해당되는 부분에는 이 헤더를 표기해 주는 경우가 많습니다.
MTA와는 전혀 관계없고, 순전히 MUA를 위해서 사용되는 Header Field라고 할 수 있습니다.



5. Content-ID, Content-Description 헤더 필드

이 두 헤더 필드의 문법은 아래와 같습니다.

id = "Content-ID" ":" "<" localpart @ domain ">"
description := "Content-Description" ":" *text

이 중 Content-ID와 같은 경우에는 평소에는 별로 중요하게 쓰이지 않지만, HTML Message 중 Embedded Image가 있는 경우에는 반드시 사용되는 중요한 Field입니다.
1. Content-Type의 종류들...

MIME의 Content-Type으로 공식적으로 등록된 것들은 얼마나 될까요? 엄청나게 많겠죠? Windows 탐색기의 파일 타입만 보더라도, 매우 많은 타입을 볼 수 있지만, 많은 응용 프로그램들이 생겨나고 있으니, 갈수록 더 늘어나겠죠.

"Text" 타입

인터넷 텍스트 메시지의 기본적인 타입입니다. 여기에 포함되는 서브 타입들을 보면...

text/plain, text/html 등등...

"Text" 타입은 charset이라고 부르는 문자 집합을 지정하는 parameter를 가질 수 있습니다.
기본 값은 앞에서도 말씀드렸듯이 US-ASCII죠.
Content-Type이 지정되지 않은 메시지 본문은 text/plain으로 처리합니다. 모든 메시지 본문의 기본 Content-Type은...

text/plain; charset=US-ASCII

요렇게 되는 거죠. charset에는 그밖에도 iso-8859-X (X : 1~10) 이라는 것이 있습니다. 한글을 비롯한 여러 국가에서 쓰이는 EUC (Extended Unix Characterset) 라는 것도 있죠. 한글 메세지의 실제로 많이 사용되는 표준 문자 집합은 EUC-KR라고 생각되네요.

"Image" 타입

이 타입은 GIF, JPEG 등의 이미지를 지원하기 위해서 처음 만들어졌습니다. 물론 Image에 해당되는 서브 타입도 아주 많지만, 거의 모든 곳에서 지원되는 타입이라면,
image/jpeg, image/gif

이 두 가지라고 할 수있겠네요.

"Audio" 타입

이 타입은 MUA가 동작하는 환경에서 이를 얼마나 지원하느냐가 문제겠죠? 그리고 Audio에 대해서는 특별한 표준이... 없습니다. MP3, Real Media 등과 같은 Audio 소스가 요즘에는 많지만, MIME에서는 공식적으로 사용하는 기본 규격은 8비트 PCM, 8KHz 규격입니다. -_-;

audio/basic

"Video" 타입

Vidoe 서브 타입도 Audio와 마찬가지로 MUA의 환경이 문제가 됩니다. 이 타입의 기본 서브타입은 MPEG으로 되어 있습니다.

video/mpeg

"Application" 타입

Application 타입은 다른 응용 프로그램이 이걸 처리해야 한다는 걸 의미합니다. 그래서 이 타입의 기본 동작은 사용자의 디스크에 저장하는게 되는 거죠. 여러 MUA에서 바로 이런 타입의 Content를 열 수 있는 기능을 지원하지만, 사실은 임시 공간에 파일을 저장하고 응용 프로그램을 부르는 방식이죠.

넘쳐나는 응용프로그램의 MIME Content-Type을 모두 인식하기란 사실상 힘들다고 볼 수 있습니다. 따라서 알 수 없는 파일의 기본 Content-Type은,

application/octet-stream

로 정의되고, 이 Content-Type에 대한 기본 동작은, "로컬 디스크에 저장"이 됩니다.

RFC에 언급되기로는 application/Postscript과 같은 서브타입이 있고, 보안 관련 이슈가 상당히 많지만, 별로 흥미가 없네요. ^^;

1. 기본 구조

"Multipart" 타입의 기본 구조를 보기 전에, Multipart 타입의 기본 서브 타입에 대해서 이야기를 해야겠네요.

Multipart Content-Type의 기본 Subtype은 "multipart/mixed"라는 서브 타입입니다. 각각의 부분은 연관관계가 없으며, 각 부분의 순서만 미미하게(?) 의미가 있는 거죠. 꼭 하나의 (특히 첫번째) 본문 부분이 inline 메시지고, 나머지는 attachment라는 보장은 없습니다. 또, 각각의 본문 부분도 multipart로 구성될 수 있습니다. 따라서 이론적으로 무한대의 중첩이 가능합니다. 실제로는 최대 세 단계 정도로 mulitpart가 구성되는 것이 일반적입니다. 어째서 세 단계까지인지는 이후에 설명하겠습니다.

맨 앞에서 메시지는 헤더와 본문으로 구성되고 둘의 구분은 NULL 라인으로 한다고 말씀드렸죠?
메시지 본문은 단순히 라인의 집합의 형태로 평면적인 구성을 하고 있기 때문에, 여러 부분으로 나누기 위해서는 각 부분의 경계를 표시할 수 있는 표식이 필요하고, 이것이 Multipart Content-Type의 기본 Parameter가 됩니다. 이 Parameter를 그걸 boundary라 부릅니다.

기본 구조를 보면 아래와 같습니다.

Content-Type: multipart/mixed; boundary=gc0p4Jq0M2Yt08j34c0p

boundary로 쓰일 수 있는 문자는 ASCII 문자 중에서 일부에 속합니다. 아래의 예는 올바른 boundary 구성이라고 볼 수 없습니다. 콜론이 들어가 있기 때문입니다. 콜론은 헤더 필드 이름과 필드 본문을 구분하기 위해서 사용되는 문자니까요.

Content-Type: multipart/mixed; boundary=gc0p4Jq0M:2Yt08j34c0p

그렇다고 완전히 틀린 건 아니고, 아래처럼 따옴표로 묶으면 적법한 boundary가 됩니다. 좀 애매한 기준이긴 합니다만, 실제로는 boundary를 Uniqueue하게 만들기 위해서 이런 식으로 쓰이는 경우도 많습니다.

Content-Type: multipart/mixed; "boundary=gc0p4Jq0M:2Yt08j34c0p"

boundary는 메시지 안에 이런 형태가 나타나지 않도록 신중하게 만들어져야 합니다. 특히, 다음에 설명할 "message" Content-Type과 같이 메시지를 가지고 있는 본문 부분의 경우에 문제가 발생할 소지가 많기 때문이죠.

multipart로 구성된 메시지의 예를 하나 보죠.

From: Nathaniel Borenstein
To: Ned Freed
Date: Sun, 21 Mar 1993 23:56:48 -0800 (PST)
Subject: Sample message
MIME-Version: 1.0
Content-type: multipart/mixed; boundary="simple boundary"

This is the preamble. It is to be ignored, though it
is a handy place for composition agents to include an
explanatory note to non-MIME conformant readers.

--simple boundary

This is implicitly typed plain US-ASCII text.
It does NOT end with a linebreak.
--simple boundary
Content-type: text/plain; charset=us-ascii

This is explicitly typed plain US-ASCII text.
It DOES end with a linebreak.

--simple boundary--

This is the epilogue. It is also to be ignored.

보면, 인자로 주어진 boundary에 두 가지 변형을 해서 boundary로 사용하고 있습니다. 첫번째는 앞에 "--"를 붙인 것입니다. 이것을 메시지 부분간의 실제 경계로 사용합니다. 그 담엔 앞 뒤에 "--"를 붙인 것이 있지요? 이건 multipart의 끝을 의미합니다.

일단 Content-Type이 multipart로 선언되면 첫번째 경계가 나타나기 전까지의 메시지는 "반드시" 무시해야 합니다. 그리고 경계가 나타나면 다음 경계가 나타나기 전까지의 부분을 하나의 본문 파트로 처리하면 됩니다. 그러다가 multipart의 끝을 나타내는 표식이 나타나면 실제 mulitpart 메시지가 끝난 걸로 처리합니다. 이후에 나타나는 모든 문자는 역시 "반드시" 무시해야 합니다.
뭐 생각보다 간단하다고 생각할 수도 있겠지만, 이 기본적인 구조를 지키지 않는 메일 시스템이 참 많습니다. boundary를 단순히 "mail-boundary"와 같이 표시하는 것들은 좀 문제를 많이 일으키죠. 또한 에필로그에 해당되는 경계를 제대로 넣어주지 않는 경우도 많이 있습니다.



2. "multipart" 타입의 각 서브 타입

이게 각각의 서브 타입들을 살펴보도록 하죠. 앞에서 본 기본 구조를 머리 속에 두고 각각의 서브 타입의 차이점들을 살펴보도록 하죠.

"Mixed" 서브 타입

앞서 말씀드린 것과 같이 mulitpart 타입의 기본 서브타입입니다. 내용은 앞과 마찬가지고, 중요한 것은, 알 수 없는 multipart의 어떤 서브 타입이 나타나더라도 처리를 못해서는 안 된다는 겁니다. 알 수 없는 multipart 서브 타입는 이 multipart/mixed 서브 타입으로 처리하도록 되어 있습니다.

"Alternative" 서브 타입

이 타입은 형식상으로는 multipart/mixed 타입과 완전히 동일합니다. 다른 점은, 이 타입은 같은 내용에 대한 서로 다른 버전을 담고 있다는 것이죠. 이 메시지를 처리하는 쪽 즉, MUA에서는 자신의 환경에 맞는 가장 좋은 버전 하나만을 선택하면 됩니다.
보통은 가장 훌륭한 버전을 맨 뒤에 놓습니다. 어떤 생각해 보면, 가장 좋은 버전이 맨 앞에 있어야 하는 것 같기도 하지만, 이런 타입을 제대로 처리하지 못하는 MUA 환경을 생각할 때, 가장 단순하고 일반적인 타입이 맨 앞에 있어야 그나마 처리가 쉬워집니다.

예를 하나 보죠.

From: Nathaniel Borenstein
To: Ned Freed
Date: Mon, 22 Mar 1993 09:41:09 -0800 (PST)
Subject: Formatted text mail
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary=boundary42

--boundary42
Content-Type: text/plain; charset=us-ascii

... plain text version of message goes here ...

--boundary42
Content-Type: text/enriched

... RFC 1896 text/enriched version of same message goes here ...

--boundary42
Content-Type: application/x-whatever

... fanciest version of same message goes here ...

--boundary42--

각각의 내용은 모두 같지만, 서로 다른 포맷을 가지는 내용을 이렇게 구분할 수 있겠죠. 이 타입을 사용하는 중요한 예는 바로 HTML 문서를 메일로 보내는 경우가 됩니다. MUA마다 HTML를 처리할 수 있는지 없는지가 달라지기 때문에, 앞부분에는 그냥 일반적인 텍스트 즉, text/plain을 넣고 그 뒤에 text/html을 넣는 겁니다.

"Digest" 서브 타입

이 서브 타입의 기본 문법은 "multipart/mixed"와 동일합니다. 다른 점은 multipart/mixed 타입에서, 각 부분의 기본 Content-Type이 text/plain인 것과는 달리 이 타입의 기본 Content-Type은 "message/rfc822"라는 겁니다.

message/rfc822라는 타입은 헤더를 포함한 메시지 자체를 나타냅니다.
즉, 메일 메시지를 캡슐화하고 있는 거라고 보면 됩니다. 보통 되돌아온 메일에 attach로 달려 있는 원래 메시지가 이 타입을 가지고 있습니다.

실제로 아직 Multipart-Digest 타입으로 된 메시지는 보지 못했습니다. 이 형태를 Multipart-Mixed 타입으로 처리해도 큰 문제는 없습니다.

예를 한 번 보죠.

From: Moderator-Address
To: Recipient-List
Date: Mon, 22 Mar 1994 13:34:51 +0000
Subject: Internet Digest, volume 42
MIME-Version: 1.0
Content-Type: multipart/digest; boundary="---- main boundary ----"

------ main boundary ----

...Introductory text or table of contents...

------ main boundary ----
Content-Type: multipart/digest;
boundary="---- next message ----"

------ next message ----

From: someone-else
Date: Fri, 26 Mar 1993 11:13:32 +0200
Subject: my opinion

...body goes here ...

------ next message ----

From: someone-else-again
Date: Fri, 26 Mar 1993 10:07:13 -0500
Subject: my different opinion

... another body goes here ...

------ next message ------

------ main boundary ------


"Parallel" 서브 타입

"multipart/mixed"와 다른 점이라고 하자면, 이 타입에서는 각각의 본문 파트가, 하드웨어에 의하든 소프트웨어에 의하든 간에 병렬적으로 디스플레이가 가능해야 한다는 거죠. 예를 들어 프리젠테이션과 같이 텍스트와 이미지와 오디오가 동시에 나타나야 하는 경우를 들 수 있겠네요. 하지만, 상당히 플랫폼의 제약을 많이 받기 때문에, 실제로 사용되는 일은 거의 없다고 보면 되겠습니다.

"Report" 서브 타입

이 타입은 현재로는 메시지의 상태를 알리기 위한 것으로 사용되고 있습니다. 즉 되돌아오는 메일 등을 이 형태로 처리하게 됩니다. 좀 더 자세한 내용은 Notification Message에서 다루도록 하겠습니다.

이 타입은 어떤 본문 파트의 일부분으로는 사용될 수 없으며, "반드시" Top Level의 Content- Type으로만 쓰이도록 되어 있습니다. 그리고 이 메시지의 전체는 반드시 7비트 ASCII 문자로만 이루어져 있어야 합니다. (실제로는 8bit로 된 경우도 존재합니다.)

이 타입의 서브 파트는 크게 두 개 혹은 세 개이고, 이 순서로 나타나야 합니다. 세번째 Part는 없을 수도 있습니다.

첫번째 부분은 사람이 알아볼 수 있는 상태 설명 부분입니다. 보통 Content-Type이 지정되어 있지 않기 때문에, Content-Type을 text/plain으로 설정해서 보게 됩니다.

두번째 부분은 기계가 파싱해서 사용할 수 있는 상태 설명입니다. Content-Type은 "message/delivery-status"와 같은 형태로 나타납니다. 이 부분도 반드시 나타나야 합니다.

세번째 부분은 선택 사항으로 원래 메시지 전체 혹은 일부분을 가지고 있습니다. 보통은 헤더에 문제가 있어서 메시지가 되돌아 오는 경우가 많기 때문에, RFC에서는 메시지 헤더만을 가지는 "text/rfc822" (실제로는 message/rfc822-headers가 더 많습니다) 타입을 권장하고 있습니다. 하지만, 요즘 같이 네트워크 용량이 풍부한 세상에서는 앞서 말씀드린 "message/rfc822" 타입으로 메시지 전체가 포함되는 것이 일반적입니다.


"Related" 서브 타입

이 타입이 multipart 타입 중에서 가장 어려운 타입이라고 볼 수 있겠네요. 이 타입은 각 본문 파트가 연관을 가지고 있다는 것을 말합니다. 그런데, 각 부분을 연결하는 방식이 응용 프로그램마다 천차만별일 수밖에 없기 때문에, 이 타입은 뭐라고 설명하기가 어렵네요.

하지만, 역시 이 타입이 중요한 이유는 HTML 문서를 메시지로 전달하기 위한 것입니다. HTML 문서에는 단순히 텍스트 뿐만이 아니라, 이미지 등의 많은 객체가 포함되어야 하는데, 거기에 바로 각 Content들을 Content-ID로 연결해서 사용하는 겁니다. 자세한 내용은 HTML 메시지에서 알아보도록 하죠.
1. "Message" 타입의 각 서브 타입

"RFC822" Subtype

앞서서 말씀드렸듯이 가장 간단하게 메일 메시지를 포함하고 있는 타입을 뜻합니다.
되돌아온 메시지에 가장 많이 포함된다고 말씀드렸죠?
"Partial" 서브 타입

메일 시스템 용량이 아무리 빠방하다 하더라도, 어떤 큰 메시지라도 끄떡없이 보낼 수 있는 건 아닙니다. 한 번에 통과할 수 있는 메시지의 크기가 여러 가지 이유로 제한이 생기기 마련이죠. 그래서, 뭔가 큰 메시지를 보내기 위해서는 여러 개의 메시지로 잘라서 보내고 받는 쪽에서 합쳐서 봐어 합니다. 그것을 위한 타입입니다.

그래서, 각각의 메시지에 몇 번째 조각이며, 전체는 몇 조각으로 되어 있는지를 표시합니다. 물론 같은 메시지의 조각임을 나타내기 위해서 id라는 parameter를 사용합니다. 아래의 예를 보죠.

3조각 메시지의 두번째 조각
Content-Type: Message/Partial; number=2; total=3;
    id="oc=jpbe0M2Yt4s@thumper.bellcore.com"
혹은,
Content-Type: Message/Partial;
    id="oc=jpbe0M2Yt4s@thumper.bellcore.com";
    number=2

3조각 메시지의 세번째 조각 - 반드시 전체 조각수를 가지고 있어서, 자신이 마지막 조각임을 알려야 합니다.
Content-Type: Message/Partial; number=3; total=3;
    id="oc=jpbe0M2Yt4s@thumper.bellcore.com"

그렇다고 메시지를 조각낼 때, 아무렇게나 조각낼 수 있는 건 아니고, 몇 가지 원칙이 있습니다.

   일단 메시지는 "반드시" 라인이 끝나는 지점에서만 잘려야 합니다.
   각 메시지 마다 Content-*, Subject, Message-ID, Encrypted, MIME-Version를 제외한 모든 헤더 필드가 덧붙여져야 합니다.
   메시지가 합쳐질 때는, 헤더 중 Content-*, Subject, Message-ID, Encrypted, MIME-Version만이 살아남고, 나머지는 무시됩니다.
   두번째 조각 이후의 헤더 필드는 깡그리 무시됩니다.

어쨌든 쉽지 않은 모양이네요...


"External-Body" 서브 타입

이 타입은 실제 내용이 메시지 내부에 있는게 아니라 외부에 있다고 알리는 건데요. 그 외부 소스의 형태가 메일, FTP, HTTP, 로칼 디스크 등 워낙 다양하기 때문에, 사용하기도 어렵고, 설명하긴 더 힘드네요. ^^;
1. 헤더 필드의 확장

일단, 문법을 좀 보죠.

encoded-word := "=?" charset "?" encoding "?" encoded-text "?="

좀 복잡하죠? 간단히 쓰자면
=? (문자집합) ? (Encoding 방식) ? (인코딩된 문자열) ?=

이렇게 되는 거죠. 여기서 문자집합은 앞서서 말씀드린 US-ASCII, ISO-8859-1, EUC-KR 등이 되는 겁니다. Encoding 방식은 그 문자들을 어떻게 Encoding했는가를 나타내구요. 각각의 지정된 내용을 ?로 구분하고 양쪽에 =?, ?=로 덮어 싸는 거죠. 물론, 여기서 문자 집합이나 Encoding에 대한 지정 방식은 대소문자를 구분하지 않습니다.



2. Encoding

여기에 사용되는 Encoding 방식은 두 가지가 있습니다.

"B" Encoding
이 방식은 말 그대로 base64 Encoding을 이용하는 겁니다. (RFC2045)

"Q" Encoding
이 방식은 Quoted-Printable과 유사한 Encoding입니다. 물론, 기본적으로는 Quoted-Printable과 같지만 몇 가지가 다르죠. 차이점을 보자면...

   "="은 "=3D"으로 SPACE는 "=20"으로 처리합니다. (16진수의 A~F는 대문자여야 합니다)
   16진수로 20은 반드시 "_"로 대치합니다. EBCDIC 코드에서는 20이 스페이스가 아니지만, 역시 무조건 "_"로 대치해야 합니다.



3. 실제 Encoding 예

아래의 예들을 보면서 실제로 사용시에 주의해야 될 점들을 살펴보죠.

Encoding된 형태 나타날 형태
(=?ISO-8849-1?Q?a?=)
     -> 당연하죠?
(a)
(=?ISO-8849-1?Q?a?= b)
     -> 역시...
(a b)
(=?ISO-8849-1?Q?a?= =?ISO-8849-1?Q?b?=)
     -> Encoding된 부분 사이의 LWSP는 없는 걸로 처리합니다.
(ab)
(=?ISO-8849-1?Q?a?=    =?ISO-8849-1?Q?a?=)
     -> LWSP가 몇 개이든 상관없습니다.
(ab)
(=?ISO-8849-1?Q?a?=
   =?ISO-8849-1?Q?a?=)
     -> CRLF도 마찬가지로 LWSP의 일부분으로 처리합니다.
(ab)
(=?ISO-8849-1?Q?a_b?=)
     -> "_"는 16진수로 20이고 ASCII 코드에서는 SPACE죠.
(a b)
(=?ISO-8849-1?Q?a?= =?ISO-8849-1?Q?_b?=)
     -> 역시 앞서 설명과 같습니다. 재확인...
(a b)


다음에는 한글 Encoding 방법에 대해서 알아보죠...

 

 

출처 : http://www.iwiz.pe.kr/bbs/view/java/article_38.html

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2009/01/14 02:25 2009/01/14 02:25

     출처  : taeyo.net

lecture Home > ASP & Mail > CDO 2.0

Transport Events Sink 를 이용한 SMTP 서비스의 효율적 사용

   강좌 최초 작성일 : 2001년 03월 29일
   강좌 최종 수정일 : 2001년 08월 08일

   작성자 : 정 진우
   편집자 : Taeyo(김 태영)

   강좌 제목 : MIME, Content-Type, Content-Transfer-Encoding..

1. 들어가며

강좌가 늦었습니다. 원칙과 신뢰, 철학적 사색속에 회사를 그만두었고, 그로 인해 ip가 있는 컴을 접하기 어려웠기에 그러합니다. 더군다나 검증되지 않는 코드를 이야기 한다는 것은 있을 수가 없는 일이기 때문에 .......

생각이 조금 맑아졌습니다. 여러분도 고민이 있으시다면 따라서 해보시지요.

1. 푸른 하늘을 많이 바라볼것.
2. 단것을 조금 섭취할것.
3. 마음이 따뜻한 사람과 대화를 나눌것.

하나 하나 생각을 정리하고, 다시 시작해야겠지요. 프로그램을 처음했던 그 때처럼. 앞으로는 엉터리 철학이지만 가끔씩 사색의 결과물을 함께 나눌 수 있도록 하겠습니다. (넘 건방지나요?)

그럼 이제 CDO2.0을 즐겨볼까요? 아참! 기간 저에게 메일을 주셨던 분이 계셨다면, 제가 이전의 메일 주소로 메일을 확인하는것이 쉽지 않아서... 아마 놓친 메일이 있을 것 같군요. 당분간은 새로운 삶의 터전이 생길때까지는 cnu97@hanmail.net 이 제 주소랍니다.

2. MIME는 어떻게 작동할까?

RFC822는 일반적인 메시지 포맷과 약간의 표준 헤더정보에 대해서 기술하고 있을 뿐이며 메시지의 body가 ASCII text 라는 점을 제외하고는 메시지의 body에 관하여 아무것도 기술하고 있지 않다.

MIME(마임)은 body text에 대하여 일정한 형식을 추가하여 사용한다. 그리고 MIME를 위한 약간의 헤더라인을 정의하고 있다. 중요한 점은 body는 여전히 ASCII text 덩어리에 불과하다는 점이다.

body에 관해서는 RFC822에 의해서 제정된 어떠한 룰도 변경되지 않았다.(단지 ASCII text면 된다.) 이러한 점이 의미하는 것은 RFC822에 적합한 메시지 전송시스템은 어떠한 변경없이 MIME 메시지를 핸들링 할 수 있다는 점이다.

메시지 전송시스템은 메시지가 7bit-text일것으로 생각한다. 또한 MIME는 행복하게도 이러한 규칙에 부합한다. 메시지 전송시스템은 약 50-700라인의 텍스트가 실행파일인지 나타내는 것인지, 어떤지에 대하여 전혀 알지 못한다.

실제로 MIME메시지가 아닌 텍스트 덩어리에 시스템을 붕괴시키는 코드가 있던 무었이든 메일전송시스템은 관여하지 않는다. 본문이 다만 7bit-ascII이면 된다. 물론 메시지를 받는 client는 text가 바이너리(이진)파일로 convert되는지에 대해서는 상당한 주의를 기울인다. MIME규칙을 해석할 메일리더기만이 이것들을 알 수 있다.

 

3. MIME Headers MIME는 약 여섯가지 부가적인 헤더라인을 가지고 있다.

이 다섯가지 헤더라인은 메시지를 받는 클라이언트에게 이 7bit-text가 어떻게 해석되어야 할 지 알려준다.

헤더라인이 의미하는 것.

MIME-Version : 메시지 인코딩의 MIME수준(level), 즉 UA(혹은 MUA->2개를 혼용하여 사용한다.) 가
                       이 메시지가 MIME 메시지로 취급되어야 함을 알려준다.
Content-Type : 메시지에 포함되어 있는 데이터 타입.
Content-Type-Encoding : 데이터가 어떤 방법으로 7bit-text로 전환되었는지에 대한 방법
Content-ID : bodypart를 구별하는 유일값.(나중에 설명)
Content-Description : MIME 응용프로그램에서는 무시되며, 단지 User가 메시지의 내용을 읽는데 도움을
                               주는 string.
Content-Desposition : MIME메시지의 bodypart에 속해 있는 메시지는 메시지에 포함되어 디스플레이되나
                                일반적으로 메시지와 분리되어 첨부파일로 표현하는 것이 대부분이다.
                                이 헤더는 순차적으로 저장되어 파일로 액세스 할 수 있도록 UA에게 알려준다.

여기에서 가장 중요한 것은 Content-Type과 Content-Type-Encoding 헤더이다.

(1) Content-Type

Content-Type 헤더는 Message Body에 포함되어 있는 데이터가 어떤종류인지 Decoder 에게 알려준다.

예)
    Content-Type:multipart/mixed;boundary="----=_NextPart_000_0042_01C0B72C.6EEDDBE0"
     Content-Type: text/html; charset="ks_c_5601-1987"
     Content-Type: image/gif; name="face.gif"
     Content-Type: text/plain; charset="iso-8859-1"

Content-Type은 "/"식별자를 이용하여, "일반적인 데이터/일반적인 테이터에 따른 세부사항" 의 형식으로 데이터의 종류를 기술하며, 데이터 타입의 정보에 따라, name=value 쌍으로 이루어진 부가적인 parameter를 가질 수 있다. 각각은 ";"으로 구분되어진다.

메일리더(전에 MUA-mail user agent 라고 하였다.)는 보다 많은 형태의 content-type을 핸들링 할 수 있다. OutLook은 text/html을 지원하며, 이것은 유저에게 디스크에 기록없이 직접 HTML메시지를 보여준다. 또한 image/jpeg를 지원하며, 메시지에 올바르게 이미지를 보여줄 수 있다.

메일리더가 지원하지 못하는 어떠한 Content type라도 디스크에 저장되어 질 수 있으며, 유저는 이것을 핸들링할 무언인가를(주로 프로그램이겠지요?)가지고 이 Content type에 따른 데이터를 열어 볼 수 있다.

다른말로 file attachment와 같은 데이터 타입은 존재하지 않는다. 이미지, 오디오 등의 데이터 타입은 존재하지만 file attachment라는 데이터 타입이 이세상에 어디에 있는가? 오직 존재하는 것은 인코딩, 디코딩된 Content-Type만 존재할 뿐이다. 메일리더가 application/zip과 같은 content-type을 해석할 수 있는가? 해석 할 수 있다면 이진 데이터 블럭을 unzip할 것이고, 그렇지 않다면, 디스크에 저장하여, user가 그것을 file attachment로 생각하게 할 것이다.(설명이 조금 어렵군요. 그러나 끝까지 읽어보면 대강 느낌이 올것 같습니다.)


(2) Content-Transfer-Encoding

이 헤더는 디코더가 메시지의 body를 원래의 포맷으로 바꾸기 위해 사용하는 메커니즘이다. 중요한 것들은 7bit, 8bit, Binary, Quoted-Printable 그리고 BASE64이다. content-type이 무엇이든지 상관없이 메일 리더는 가장 먼저는 메시지를 decoding할 수 있어야 한다. 만약 메일리더가 image/gif를 지원하지 않는다 할지라도 앞에서 언급한 것처럼 디스크에는 기록될 수 있어야 한다. 프로그램이 모든 인코딩 매커니즘을 다룰 수 없다면, 이것은 불가능하다.

운좋게도, 단지 BASE64encoding만이 사소한 문제가 있을 뿐(아마 old unix버전의 mail reader가 그럴 것이다.)이다.

 

4. Multi-Part Messages

MIME는 body에 이미지가 들어있다던지, 아님 첨부파일이 있다던지, 하는 것을 처리하기 위해 각각의 영역을 part로 분할 하여 놓았으며, 이 part가 전부 합쳐져 메시지의 본문을 구성한다. 이러한 형태의 MIME 메시지를 Multi-Part 메시지라 한다.

< P>예)<br>    Content-Type:multipart/mixed;boundary="----=_NextPart_000_0042_01C0B72C.6EEDDBE0"
     Content-Type: image/jpeg;boundary="Myimagebound"
     ------=_NextPart_000_0042_01C0B72C.6EEDDBE0 \

위에서 언급된 boundary 스트링을 보고 이 부분을 찾아서 MIME를 해석한다.

------=_NextPart_000_0042_01C0B72C.6EEDDBE0--
--Myimagebound
여기에 이미지가 인코딩되어있는 문자열이 들어간다.(넘 당연한 소리인가?)
--Myimagebound--

boundary 스트링은 Content-Type header의 특별히 정의된 파라미터이다. 이 스트링을 보고, MIME는 각각의 Part를 인식한다. boundary의 value로 "--"문자열을 사용해서는 안된다. 이것은 bodypart의 시작과, 끝을 나타낼때 사용한다. ----,나 ------등은 상관없다. 또한 part가 끝날때에는 마지막에 "--"을 덧붙인다.

개인적으로 outlook은
Content-Type:multipart/mixed;boundary="----=_NextPart_000_0042_01C0B72C.6EEDDBE0"  이렇게 복잡하게 하는데 개인적으로는 좀더 줄여서 NextPart_000_0042이정도만 표현해도 좋을것 같다.(솔직히 인간MUA가 되어서 해석하기에는 너무 짱난다.)

boundary의 value값을 정하는데에는 규칙은 없으며, 다만 그 메시지에서 중복되지 않는 String값이면 된다. 이제부터는 아웃룩에서 메시지 하나를 뽑아낸후 그 헤더와 본문을 유심히 살펴보아야 이 강좌가 이해가 될 것이다.)

 

5. 그럼 이제 본격적으로 분석해 보자

주석의 형태로 설명하며, 주석은 전부 녹색으로 처리한다. 그렇다고, 메일에 주석이라는 것이 존재하는 것은 결코 아니다. 앞으로 나올 강좌의 메일 내용을 보고 싶으면, 그냥 복사해서 주석을 제거한 다음 notepad에 붙여 .eml로 저장한후 outlook으로 열어보면 된다.

Received: from speed (SPEED25 [210.102.9.155]) by chaosdb.chaostrade with SMTP (Microsoft Exchange Internet Mail Service Version 5.5.2448.0)
id HLLR7HZX; Wed, 28 Mar 2001 01:58:44 +0900
Message-ID: <004701c0b6e0$ff27c5a0$9b0966d2@elim.net>
'메시지와 메시지 객체를 구별하는 고유값이다.

From: =?ks_c_5601-1987?B?waTB+L/s? = <cnu97@hanmail.net>
'BASE64로 인코딩 되어있다. 전에 강좌에서 NewMail객체를 이용하여 메일주소가 아닌
'예명으로 메일을 보낼수 있다고 그랬는데, 여러분의 주소로 메일을 보낸후
'From이하의 ?--?를 복사해서 Newmail객체의 To에 붙이고서 메일을 발송해보라!
'그럼 예명이 들어갈 것이다.

To: <cnu97@hanmail.net>
Subject: test
Date: Wed, 28 Mar 2001 02:11:43 +0900
MIME-Version: 1.0
'MIME버전이다.

Content-Type: multipart/mixed;
boundary="----=_NextPart_000_0042_01C0B72C.6EEDDBE0"
'앞의 일반적인 데이터 형을 보니 복합part를 가지고 있다. 각각의 part를 bodypart라고 한다.
'그리고 뒤의 세부내용을 보니 mixed다. 뭔가 여러가지가 짬봉이 되어있다는 생각이 드는가?
'이제 boundary영역을 보면 뭐 복잡하게 되어있는데 이 부분의 part를 참조하라는 말이다.

X-Priority: 3
'메시지의 우선순위이다.
'이개념에 대해서 잠깐 생각하면, 외국넘들은 별로 원칙적이도 않은것 같은데
'나름대로는 꽤 원칙적이라고 떠든다.(어떻게 보면 융통성이 없다.)
'FAX나 MAIL이 오면 아무리 시급하더라도, 비서가 이것을 프린트해서 대장한테 가져다
'줄때는 언제나 날라온 순서대로 준다.(물론 이렇지는 않겠지만, 고객주문의 경우를 생각하면..)
'아무리 본문에 넘급함, 넘급함 외치고 외쳐도, 소리없는 아우성이다.
'절대 먼저 처리해주지 않는다. 먼저온것부터 처리, 그러다가 퇴근시간이 되면 칼같이
'집에 간다. 그래서 생긴것이 우선순위이다. 메시지에 급합, 나중뭐 이런것이 붙어있으면
'먼저온것 위에 살포시 포개준다. 완전히 이 헤더는 외국넘들의 습관에 따른 것이다.
'자랑스러운 한국인을 보라. 대충 메일 내용읽고, 나름대로의 중요도를 판단해버리지 않는가?
'무지 영리한 민족이다.

X-MSMail-Priority: Normal
'위에선 쓴 X-Priority와 하는 짓거리와(음 비어가 , 좀 흥분했나!!) 같다.
'outlook이 X-Priority를 좀더 쉽게 읽을려고, 나름대로 변형해서 붙여버렸다.

X-Mailer: Microsoft Outlook Express 5.50.4522.1200
'MUA 버전이다.

X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4522.1200
'OutLook Mime해석기의 버전이다.

This is a multi-part message in MIME format.
'여기서부터 본문시작이다. 단지 ASCII text에 불과하다.

------=_NextPart_000_0042_01C0B72C.6EEDDBE0
Content-Type: multipart/related;
type="multipart/alternative";
boundary="----=_NextPart_001_0043_01C0B72C.6EEDDBE0"
'가장 먼저 나왔던 boundary를 따라가 보니 이것이 나왔고, 이것은 다음으로 참조할
'bodypart를 알려준다. 역시 multipart이다.

------=_NextPart_001_0043_01C0B72C.6EEDDBE0
Content-Type: multipart/alternative;
boundary="----=_NextPart_002_0044_01C0B72C.6EEDDBE0"
'위에서 언급한 boundary를 따라가 보니 다른 part를 참조하라구 한다.(짱난다.)

------=_NextPart_002_0044_01C0B72C.6EEDDBE0
Content-Type: text/plain;
charset="ks_c_5601-1987"
Content-Transfer-Encoding: base64

vsiz58fPvLy/5C4gDQpDRE8yLk/A1LTPtNkuDQogDQrAzLnMwfYgx8+zqiDDt7rOx9/AvQ0K
'content-type은 text/plain이구 charset="ks_c_5601-7987" 이구
'만약 charset이 생략되면 US-ASCII로 지정된다. 이 값이 default값이다.
'울 나라가 좀만 더 발전되면 기본값이 ks_c.... 이 값이 될 것이다.
'MUA가 인코딩한 방식은 base64라고 되어있다.
'위에 무슨 암호와 같은 것은 "안녕하세요.CDO2.0입니다."이 문자열을 인코딩한 것이다.

------=_NextPart_002_0044_01C0B72C.6EEDDBE0
Content-Type: text/html;
charset="ks_c_5601-1987"
Content-Transfer-Encoding: base64

PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv
L0VOIj4NCjxIVE1MPjxIRUFEPg0KDQo8TUVUQSBjb250ZW50PSJNU0hUTUwgNS41MC40NTIyLjE4
MDAiIG5hbWU9R0VORVJBVE9SPg0KPFNUWUxFPjwvU1RZTEU+DQo8L0hFQUQ+DQo8Qk9EWSBiZ0Nv
bG9yPSNmZmZmZmY+DQo8RElWPjxGT05UIHNpemU9Mj6+yLPnx8+8vL/kLiA8L0ZPTlQ+PC9ESVY+
DQo8RElWPjxGT05UIHNpemU9Mj5DRE8yLk/A1LTPtNkuPC9GT05UPjwvRElWPg0KPERJVj48SU1H
IGFsdD0iIiBoc3BhY2U9MCBzcmM9ImNpZDowMDQxMDFjMGI2ZTAkZmYwNjMzZTAkOWIwOTY2ZDJA
ZWxpbS5uZXQiIA0KYWxpZ249YmFzZWxpbmUgYm9yZGVyPTA+PC9ESVY+DQo8RElWPjxGT05UIHNp
emU9Mj7AzLnMwfYgx8+zqiDDt7rOx9/AvTwvRk9OVD48L0RJVj48L0JPRFk+PC9IVE1MPg0K
'이것은 text/html이구 역시 내용은 "안녕하세요.CDO2.0입니다." 를 html로 바꾸어놓은
'것이다. 이시점에서 보건데, alternative라는 것은 양자택일이다.
'boundary값도 같다. 즉 MUA가 머리가 영리해서, html을 표시할 수 있으면 이것을
'이용하고 그렇지 않으면, 그냥 텍스트를 사용하라는 것이다.
'Content-Type:multipart/alternative;->의 의미는 바로 이것이다.
'만약 메일리더가 html을 모르는 녀석일때, text에 html을 지원하지 않습니다. 라는
'말을 덧붙이고 싶으면, 위의 text/plain의 부분에 이 말을 써주면 된다.
'outlook은 메시지의 본문을 보고 동일하게 이 2개의 값을 만들어낸다.
'물론 cdo2.0을 사용하면 그냥 모든것을 핸들링 할 수 있다.

------=_NextPart_002_0044_01C0B72C.6EEDDBE0--
'뒤에 "--"가 붙어있는 것으로 봐서 이 part의 끝이다.
'아래에서 두번째 part가 시작된다.

------=_NextPart_001_0043_01C0B72C.6EEDDBE0
Content-Type: image/gif;
name="face.gif"
Content-Transfer-Encoding: base64
Content-ID: <004101c0b6e0$ff0633e0$9b0966d2@elim.net>
'gif파일이구, 이름은 face.gif이다. 본문에 텍스트가 아닌 그림등이 삽입
'될 때에는 name value가 들어간다. 당연 outlook으로 그림 못그리니깐
'삽입이라는 것도 파일첨부하고 같다. 다만 content-type만 다르다.
'드디어 Content-ID가 나왔다. 각각의 bodypart를 구별하기 위한 고유값이라고
'언급했다. 메시지ID는 각 메시지간에 구별을 위한 고유값이다.

R0lGODlhLAAsANU/AP39+vrLIfnKHOzs7P3SK9rY0vbSTfzup/K8Cv7siayNGP/qItXMrNXTyvbF
G/3XHm9YE/f28xULA/XCFf3XOf3lc+nObMCjGfrLFv3hIPrGC/jFFcO9q//63pJ2FdTFj9vFd/71
xv3gV/fIHPvOJenJHvjHGPTflNHOxN/e2/XMNUczCufEPOrXIePctvLDH+Pi4em7IPjJIOHCHdjB
HdW0HP3PDcnFuIBxUOPHW/Ds1ODATu7cOfLFKPfHH////yH5BAEAAD8ALAAAAAAsACwAQAb/wJ9w
SBwCOp1DRURpVg6hDqBIrQoBoqgI0yQJBCSCOEAKmAMC9PeLMQUmL920GKoAKhneSlJ6yNBnMmmC
f2aFDg8ZEBI0DxMbGxgfBSkDPwAGAWIEJGUyMg8LLQqLEqamKx4KJRkBPiMjJiYOGyYjGyocDZQw
RAAWCDKwDn+fsjIODrfJjyaQzggvTxwoKLspMBFWRgADMCkFBQ3j5OW74SnY2QBz25d1IT91NisQ
C5xlJBkrKw9eXwgQxHP3I8kPBhIgUHiwiUAgTmnMlDEDRsCtBR5M1XjgYp2QBBRAhpGx4IKpCwse
vBLwaYQDH69C0djDKIODNpAi5bhm6ccB/wSdZHQK8KcTy0MOBNiS9QWWs1obJlRwccMapZ5UBrjY
EXBCMh8TJrj0GhYOAgwsPlStdg3GgHbbAIRIIEKEARUMxfgjUSMGhoAqDsAlOGTupQo2SDSJocBf
0QAjHvgZkQbDlwkITgwuYtCFBxYUBBCgwAmfxIlfhhKyCMHDAwwu3voS7KJUjQxChQI6E/ELUaFN
M2RssQBwg0pTDojoYEB0iz0KFhClyNLQJ0MOMpRYZA/DBFkONOzEFiHEAyYT/5Tcs+JCogzwMzyY
oYAmBFaUTWDIOUEAiLbyYKBJeoAI1cl78EmGAS1QbRALJAJEJQIDVmFTGAIjGOIDRZ/I8P/KCMgQ
45QzziSFmQoJMFBVW5tFAIxXyvigDDIezlKLLJCE9QIFJ1DDFi/auNMNOAyAsEMMMYQVzQsssACC
WtVYcw42shHmCzsReJPOllzC4OUAAwRpZRVyVbCQDRh0gqYGNtiggQgHRLDZmEJ0kEACUhyAgz1l
+JMIPxl4oQECBoQwZ1xzsZMAATYoskJKEgmQwQUbWbYGZppZ2cFym2IwGgEYSOYJGkOlsYalESIg
WFwHHPBDAjaM5kUYDeUjCEVGfRFJIuJVOZsUOEgAWq0S8eZJIakJEOoiHmRgAHJEhBBCBMEq5BAZ
u0UkSETUoRFZCQl54IENFpBXZwIAJFD/kgQeLDCRJ2Nwi2sZET5AQ0ILWFYLA+Yq0QEFJCygQEKB
FqLGb4MQlYYPiTC7gCyzmAACL+lmATABopzkbiEdelgILBk8J8EKLTzgoH7h7XTVASSIsIkg67Kb
oADKJBNAIg9kpNECteznzAQY/MdLB2IALNEf2ulczwVMk3JKe5LZQstTkJDwAYAJaCBGUIX4IEAo
812gwNgxSCafA7K8gmMtDhBgwQ0AYiKawdwee91XTjkIoo0uIYAiNTxdYcAGE1lniCEuob0B2haR
CMkImBlwgI9AGnECAq7Acp0JyIDY0gg+yNIMiSMg0MNUa/E0GAA5YBgLZUcNY8KHEJPoYgACMYiQ
AAepp+NrERGAkKQDXkUMeiwTvBJVVHC47WOFHsU1QAoMcBVQV0pibzqUbLX1u5DTg1MNAx+A8OQH
KkYpJTpUHhoXAFmmE8789FOy5Zfu08kO/GB66T+YEZCTlYIAADs=

------=_NextPart_001_0043_01C0B72C.6EEDDBE0--
'part끝
'part 다시시작

------=_NextPart_000_0042_01C0B72C.6EEDDBE0
Content-Type: image/gif;
name="icn_gongoo.gif"
Content-Transfer-Encoding: base64
Content-Disposition: attachment;
filename="icn_gongoo.gif"
'이 한줄의 추가로(Content-Disposition) 본문에 삽입되지 않고, 첨부파일 형태로 된다.
'Content-Disposition:attachment를 attachment를 inline으로 바꾸어 보라.
'Content-Dispositon의 value값은 attachnet, inline이다. 그외의 파일
'이름이라든가, 파일사이즈 등이 있는데, msdn을 참고하면된다. 이 강좌 마지막에
'참고라는 index가 있는데, 여기를 따라가서 msdn을 보면 잘나온다.
'이제 이 부분을 빼고(Content-Disposition:attachment를 삭제해 보라)
'한번 메일을 읽어보면, 거의 모든 것을 이해하게 될것이다.
'여기에서 하나 생각해 볼 문제는 아무리 프로그램 교환에 대한
'감시가 있더라도 이부분만을 notepad에 붙여서 메일로 전송하면
'받은 사람은 역시 이것을 가지고서, 쉽게 이진 파일을 복원할 있을 것이다.
'그러나 이런 방법으로 프로그램 교환이나 그런것을 하지 말기를 바란다.
'우리는 건전한 프로그래머 아닌가?
'다시말하면, 자료저장 방식을 메일처럼 text로 할 수도 있다는 말이다.
'이것을 응용하면 뭔가 할 수도 있을것 같은데...

R0lGODlhLgAoAMT/AHmGxTLLMmWYZYTTM43WQazhdbznkM3trNzyxeX20/7//XXUBorbK6roYbTq
dMTzjff88fD55fr99vv9+HmiFO//fv/wAP9lMnVqak5NTcDAwMvLy5iYmH19fVtbWwAAACH5BAEA
ABoALAAAAAAuACgAQAX/oCaOY0SeaKquqge8ryePnmBfuKzvcuZnmJNnwWg8jo5kY7lkOJ/PhXRK
BbJEHyNSyWxAv9Rq8PrpdD5ls3rNZqPfaNbBUIhIRpDE/crHWj5XOjAwHgGGhh4VihU8PGIrQ0VH
D0kOXV5fUWFTVn2eKT4noX1wWB0aaYBkahtmqid2KQcHJp+2JxMIBHVCOixvKx8Ww50tg4SIizuL
ih4Uz88eP2NCRFqUXEyZmptSxSmR15WX207d3tQt1pPjXeUM5999jfT1vhqjpGlt/P1ufGVQuRpR
CsUHDghVldnQ6tUtgQM9FbRF6+GtAwgQoEhgIIFFFQ5JRDgwwIDGj7+GosVBoSABgj0iXBBCoQPH
BQ+QiMkTcgxAoQA7bAhY1gzaM3w+0tHs+TMZs0RPo8lYkFQdA3v2uHXbSSIcu2xNyp1Dx8LrFkvu
xMZTSnPdWXJqt7KtJult2m1juZ74UBcbWm1xw+hNgcYuYLxUdAxGiSKfCMf64EieTFly5DKVM2sO
SdiVq81wEr5KJXGNQoicUa1M9aGhxVQRV6lJ/QkYYxQhAAA7e09KBy8Px5HhyFHgQLOCbe3RRXFh
Q4d1Iy5W6Phi4K+S/TEGWPnw5X2KNVMO+BjxERqhJ3Im7dkmjcmNWc/RYnoqko8eXQxLxru3b985
C/0eTrwmkpuHiieD6ayZpZDNWR7X2YwGTW4onU8qqRSScaVBAAA7

------=_NextPart_000_0042_01C0B72C.6EEDDBE0
Content-Type: text/plain;
name="check.txt"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment;
filename="check.txt"

OK
'인코딩 방식이 :7bit로 되어있다.

------=_NextPart_000_0042_01C0B72C.6EEDDBE0--

 

6. 참고

(1) 다음은 RFC에 나와이는 MIME에 관한 번호이다.(졸라 많다.)

822, 934, 1000, 1036, 1039, 1049, 1314, 1341, 1486, 1494, 1495, 1521, 1522, 1601, 1602, 1652, 1730, 1738, 1847, 1866, 1867, 1892, 1894, 1896, 1911, 2000, 2015, 2017, 2026, 2045, 2046, 2047, 2048, 2049, 2068, 2076, 2077, 2110, 2111, 2112, 2122, 2183, 2184, 2220, 2231, 2234, 2298, 2301, 2311, 2318

(2) MIME헤더를 보다 깊게 보고 싶으면 MSDN Library에 MIME Headers라는 항목이 있는데, 여기를 살펴보면 된다. 참고적으로 MSDN Library를 찾아보는 연습은 대단히 중요하기에. 세세한 링크나 위치는 적지 않는다. 위치를 찾는데 어려움이 따르면, 아래의 이미지를 참조해서 찾아나가길 바란다. 그저 이것저것 눌러보면, 대강 라이브러리의 전체 내용이 보이고, 그럼 내공향상에 엄청 도움이 될 것이다.

(3) 위의 내용을 참고하여 MSDN을 뒤져서, Content-Type의 헤더 값을 그냥 바꾸어 보라. 그럼 메시지가 UA에서 어떤 형태로 보여지는지 살펴 볼 수 있다. 이정도 파악이 되면, 여러분은 이제 인간 outlook express라고 불린다. 즉 Content-dispositon: attachment 라고 되어 있는 것을 attachment대신 inline으로 바꾸어
보는 것과 같은 연습을 말한다. 한번 바꾸어 보라.

(4) 위의 헤더 값중, 디지털 서명과 관련한 헤더값이 몇가지 있는데, 디지털 서명과 관련된 테스트및 기타의 문제는 강좌 끝마칠 정도에 설명할까 한다.

(5) msdn 및 RFC에 나와있는 헤더값중 중요한 것은 강좌 곳곳에 설명하기로 한다.

(6) 이상의 것을 이해한다면, 이전버전의 cdoNTS의 NEWMAIL객체를 통해서도 나름대로의 조작을 통해서 웹페이지 첨부라든가 하는 것을 할 수 있을 것이다. 물론 약간의 사고가 필요하다. 이 역시 강좌 곳곳에 설명하기로 한다.

(7) 이번 강좌는 그냥 강좌를 읽어보는 수준이 되어서는 안된다. 자기자신에게 수통의 메일을 보내고 그 파일을 조작하고, 세심히 눈으로 내용을 읽어 가는 과정이 필요하다. 실질적으로 이 과정을 통하면, 다음 CDO 개체 모델이 눈에 들어오며, 개체 모델의 파악이 끝나면, 여러분은 CDO2.0을 가지고 아이다루듯이 자연스럽게 프로그래밍을 할 수 있다. 메일의 모든 헤더내용과, 모든 의미를 파악할 수 있다는 것-멋진 일이 아닌가!!!!

 

7. 마치면서

무려 4시간이나 고민하면서 기록해던 강좌가 그만 버튼 하나 잘못눌러서 날아가 버렸습니다. 이때의 황당함이란......

강좌를 적어놓고 한번 읽어보니, 이번강좌는 정말 어리숙하다는 생각이 듭니다. MIME를 설명하기 위해, 모든 헤더값등을 적는다는 것은 강좌로서는 불가능하다는 생각이 들었습니다. 나름대로는 가장 중요한 개념을 압축하여 놓았다고 생각하지만... 기타의 것은 MSDN을 참고하시면 됩니다. 그냥 쉽게 읽을 수 있을 것 같군요.(?) 여기에서 8bit니 base64니 하는 알고리즘을 언급하지 않았습니다. 솔직히 저도 공부하지는 않아서 로직은 잘 모릅니다. 텍스트 파일은 인코딩로직이 그리 어렵지 않으나, 이진 파일은 힘이 듭니다.

다음다음 강좌에 ASP로 구현된 BASE64디코딩, 인코딩 함수를 첨부하겠습니다. 이 부분은 관심이 있으시면, 인터넷을 통해서 나름대로 공부했으면 합니다. 나름대로는 CDO2.0 개체모델을 이해하기 위해서는 이정도면 충분하다고 생각합니다.

몇가지 언급하지 않은 부분과 빼먹은 부분은 IBODYPart 개체모델(정확이는 com 인터페이스) 에 대해 이야기 할때 좀더 덧 붙일까 합니다. CDO를 이용하면, DB에 BASE64로 인코딩해서 패스워드를 집어넣고, 다시 인코딩 할 수 있습니다. 이것에 관한 메일이 몇통 있었는데, 개인적으로는 암호화도 아니고, 그런데 굳이 이런 것이 보안에 그리 효용이 있을까 하는 생각을 해봅니다. 차리리 다른 쪽에 좀더 신경을 쓰는 것이..

다음 강좌부터는 기본적인 개요는 이정도로 하기로 하고, 이제 CDO object 에 대해서 이야기 드리겠습니다. 그 때부터는 코드가 많이 나올것 같군요. vb를 좀 건드려 볼까요? (아직은 .......) 그럼 여러분 다음 강좌에서 뵙겠습니다.

언제나 처음처럼

 

 

크리에이티브 커먼즈 라이센스
Creative Commons License
이올린에 북마크하기(0) 이올린에 추천하기(0)
2009/01/06 07:40 2009/01/06 07:40