如何从原始电子邮件中提取信息
How to extract Information from Raw Email
到目前为止我做了什么
我使用 POP3 包来阅读我邮箱中的所有电子邮件。
我收到了来自 POP3
函数的原始电子邮件,如下例所示。 (我省略了一些信息)
问题
我遇到了从中提取信息的问题。
我使用 mail 来提取信息,但不幸的是,这个包无法从原始电子邮件中提取信息。
寻求帮助
有什么方法或软件包可以帮助我从原始电子邮件中提取信息吗?
我试过的方法
// Retrieve all the email from your mailbox
msgs, _, error := connection.ListAll()
// Convert a chunk of integer to raw email
data, _ := connection.Retr(msgs[0])
// Extract Email Address
to, _ := mail.ParseAddress(data)
我遇到的错误
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x5819ed]
原始电子邮件示例
From:
To:
Subject:
Thread-Topic:
Thread-Index: AdPgWzcFT3FjbSbUT1ycoU2ioB1bKAAAAHuA
X-MS-Exchange-MessageSentRepresentingType: 1
Date:
Message-ID:
Accept-Language: en-SG, en-US
Content-Language: en-US
X-MS-Exchange-Organization-AuthAs: Internal
X-MS-Exchange-Organization-AuthMechanism: 04
X-MS-Exchange-Organization-AuthSource:
X-MS-Has-Attach:
X-MS-Exchange-Organization-Network-Message-Id:
8c1e141b-c3ba-4471-0526-08d5b3b59967
X-MS-TNEF-Correlator:
Content-Type: multipart/alternative;
boundary="_002_b1a01aa36e1c4b3d9969a7bbb856bd3b"
MIME-Version: 1.0
--_002_b1a01aa36e1c4b3d9969a7bbb856bd3b
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: base64
PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVy
bjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVt
YXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWlj
cm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv
VFIvUkVDLWh0bWw0MCI+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg
Y29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRv
ciIgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTUgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPHN0eWxl
PjwhLS0NCi8qIEZvbnQgRGVmaW5pdGlvbnMgKi8NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6
IkNhbWJyaWEgTWF0aCI7DQoJcGFub3NlLTE6MiA0IDUgMyA1IDQgNiAzIDIgNDt9DQpAZm9udC1m
YWNlDQoJe2ZvbnQtZmFtaWx5OkRlbmdYaWFuOw0KCXBhbm9zZS0xOjIgMSA2IDAgMyAxIDEgMSAx
IDE7fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseTpDYWxpYnJpOw0KCXBhbm9zZS0xOjIgMTUg
NSAyIDIgMiA0IDMgMiA0O30NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6IlxARGVuZ1hpYW4i
Ow0KCXBhbm9zZS0xOjIgMSA2IDAgMyAxIDEgMSAxIDE7fQ0KLyogU3R5bGUgRGVmaW5pdGlvbnMg
Ki8NCnAuTXNvTm9ybWFsLCBsaS5Nc29Ob3JtYWwsIGRpdi5Nc29Ob3JtYWwNCgl7bWFyZ2luOjBj
bTsNCgltYXJnaW4tYm90dG9tOi4wMDAxcHQ7DQoJZm9udC1zaXplOjExLjBwdDsNCglmb250LWZh
bWlseToiQ2FsaWJyaSIsc2Fucy1zZXJpZjt9DQphOmxpbmssIHNwYW4uTXNvSHlwZXJsaW5rDQoJ
e21zby1zdHlsZS1wcmlvcml0eTo5OTsNCgljb2xvcjojMDU2M0MxOw0KCXRleHQtZGVjb3JhdGlv
bjp1bmRlcmxpbmU7fQ0KYTp2aXNpdGVkLCBzcGFuLk1zb0h5cGVybGlua0ZvbGxvd2VkDQoJe21z
by1zdHlsZS1wcmlvcml0eTo5OTsNCgljb2xvcjojOTU0RjcyOw0KCXRleHQtZGVjb3JhdGlvbjp1
bmRlcmxpbmU7fQ0KcC5tc29ub3JtYWwwLCBsaS5tc29ub3JtYWwwLCBkaXYubXNvbm9ybWFsMA0K
CXttc28tc3R5bGUtbmFtZTptc29ub3JtYWw7DQoJbXNvLW1hcmdpbi10b3AtYWx0OmF1dG87DQoJ
bWFyZ2luLXJpZ2h0OjBjbTsNCgltc28tbWFyZ2luLWJvdHRvbS1hbHQ6YXV0bzsNCgltYXJnaW4t
bGVmdDowY207DQoJZm9udC1zaXplOjEyLjBwdDsNCglmb250LWZhbWlseToiVGltZXMgTmV3IFJv
bWFuIixzZXJpZjt9DQpzcGFuLkVtYWlsU3R5bGUxOA0KCXttc28tc3R5bGUtdHlwZTpwZXJzb25h
bC1jb21wb3NlOw0KCWZvbnQtZmFtaWx5OiJDYWxpYnJpIixzYW5zLXNlcmlmOw0KCWNvbG9yOndp
bmRvd3RleHQ7fQ0KLk1zb0NocERlZmF1bHQNCgl7bXNvLXN0eWxlLXR5cGU6ZXhwb3J0LW9ubHk7
DQoJZm9udC1zaXplOjEwLjBwdDsNCglmb250LWZhbWlseToiQ2FsaWJyaSIsc2Fucy1zZXJpZjt9
DQpAcGFnZSBXb3JkU2VjdGlvbjENCgl7c2l6ZTo2MTIuMHB0IDc5Mi4wcHQ7DQoJbWFyZ2luOjcy
LjBwdCA3Mi4wcHQgNzIuMHB0IDcyLjBwdDt9DQpkaXYuV29yZFNlY3Rpb24xDQoJe3BhZ2U6V29y
ZFNlY3Rpb24xO30NCi0tPjwvc3R5bGU+PCEtLVtpZiBndGUgbXNvIDldPjx4bWw+DQo8bzpzaGFw
ZWRlZmF1bHRzIHY6ZXh0PSJlZGl0IiBzcGlkbWF4PSIxMDI2IiAvPg0KPC94bWw+PCFbZW5kaWZd
LS0+PCEtLVtpZiBndGUgbXNvIDldPjx4bWw+DQo8bzpzaGFwZWxheW91dCB2OmV4dD0iZWRpdCI+
DQo8bzppZG1hcCB2OmV4dD0iZWRpdCIgZGF0YT0iMSIgLz4NCjwvbzpzaGFwZWxheW91dD48L3ht
bD48IVtlbmRpZl0tLT4NCjwvaGVhZD4NCjxib2R5IGxhbmc9IkVOLVNHIiBsaW5rPSIjMDU2M0Mx
IiB2bGluaz0iIzk1NEY3MiI+DQo8ZGl2IGNsYXNzPSJXb3JkU2VjdGlvbjEiPg0KPHAgY2xhc3M9
Ik1zb05vcm1hbCI+PG86cD4mbmJzcDs8L286cD48L3A+DQo8L2Rpdj4NCjxicj4NCjxociBhbGln
bj0ibGVmdCIgc3R5bGU9Im1hcmdpbi1sZWZ0OjA7dGV4dC1hbGlnbjpsZWZ0O3dpZHRoOjUwJTto
ZWlnaHQ6MXB4O2JhY2tncm91bmQtY29sb3I6Z3JheTtib3JkZXI6MHB4OyI+DQo8Zm9udCBzdHls
ZT0iY29sb3I6Z3JheTsiIHNpemU9Ii0xIj5UaGlzIGVtYWlsIHdhcyBzY2FubmVkIGJ5IEJpdGRl
ZmVuZGVyPC9mb250Pg0KPC9ib2R5Pg0KPC9odG1sPg0K
--_002_b1a01aa36e1c4b3d9969a7bbb856bd3b
Content-Type: text/calendar; charset="utf-8"; method=REQUEST
Content-Transfer-Encoding: base64
QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UkVRVUVTVA0KUFJPRElEOk1pY3Jvc29mdCBFeGNoYW5n
ZSBTZXJ2ZXIgMjAxMA0KVkVSU0lPTjoyLjANCkJFR0lOOlZUSU1FWk9ORQ0KVFpJRDpTaW5nYXBv
cmUgU3RhbmRhcmQgVGltZQ0KQkVHSU46U1RBTkRBUkQNCkRUU1RBUlQ6MTYwMTAxMDFUMDAwMDAw
DQpUWk9GRlNFVEZST006KzA4MDANClRaT0ZGU0VUVE86KzA4MDANCkVORDpTVEFOREFSRA0KQkVH
SU46REFZTElHSFQNCkRUU1RBUlQ6MTYwMTAxMDFUMDAwMDAwDQpUWk9GRlNFVEZST006KzA4MDAN
ClRaT0ZGU0VUVE86KzA4MDANCkVORDpEQVlMSUdIVA0KRU5EOlZUSU1FWk9ORQ0KQkVHSU46VkVW
RU5UDQpPUkdBTklaRVI7Q049SG8gU2lldyBLZWU6TUFJTFRPOkhPX1NpZXdfS2VlQGlwaS1zaW5n
YXBvcmUub3JnDQpBVFRFTkRFRTtST0xFPVJFUS1QQVJUSUNJUEFOVDtQQVJUU1RBVD1ORUVEUy1B
Q1RJT047UlNWUD1UUlVFO0NOPUtvaCBXZWUgSG8NCiBuZzpNQUlMVE86S09IX1dlZV9Ib25nQGlw
aS1zaW5nYXBvcmUub3JnDQpERVNDUklQVElPTjtMQU5HVUFHRT1lbi1VUzpcblxuX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fX19cblRoaXMgZW1haWwNCiAgd2FzIHNjYW5uZWQgYnkgQml0
ZGVmZW5kZXJcbg0KVUlEOjA0MDAwMDAwODIwMEUwMDA3NEM1QjcxMDFBODJFMDA4MDAwMDAwMDA0
MDEzMTY0NzlFRTBEMzAxMDAwMDAwMDAwMDAwMDAwDQogMDEwMDAwMDAwMzQ5NDcwQUMzMzQ0NzM0
MDk5QzM0OEE0M0E0M0ZCREMNClNVTU1BUlk7TEFOR1VBR0U9ZW4tVVM6SFIgT3JpZW50YXRpb246
IEtvaCBXZWUgSG9uZyAoQU0gLSBEaWdpdGFsIFBsYXRmb3Jtcw0KICkNCkRUU1RBUlQ7VFpJRD1T
aW5nYXBvcmUgU3RhbmRhcmQgVGltZToyMDE4MDUwN1QxNDAwMDANCkRURU5EO1RaSUQ9U2luZ2Fw
b3JlIFN0YW5kYXJkIFRpbWU6MjAxODA1MDdUMTUzMDAwDQpDTEFTUzpQVUJMSUMNClBSSU9SSVRZ
OjUNCkRUU1RBTVA6MjAxODA1MDdUMDA1ODA2Wg0KVFJBTlNQOk9QQVFVRQ0KU1RBVFVTOkNPTkZJ
Uk1FRA0KU0VRVUVOQ0U6Mw0KTE9DQVRJT047TEFOR1VBR0U9ZW4tVVM6Q29ubmVjdGlvbg0KWC1N
SUNST1NPRlQtQ0RPLUFQUFQtU0VRVUVOQ0U6Mw0KWC1NSUNST1NPRlQtQ0RPLU9XTkVSQVBQVElE
OjEzMDY0MTMwMjYNClgtTUlDUk9TT0ZULUNETy1CVVNZU1RBVFVTOlRFTlRBVElWRQ0KWC1NSUNS
T1NPRlQtQ0RPLUlOVEVOREVEU1RBVFVTOkJVU1kNClgtTUlDUk9TT0ZULUNETy1BTExEQVlFVkVO
VDpGQUxTRQ0KWC1NSUNST1NPRlQtQ0RPLUlNUE9SVEFOQ0U6MQ0KWC1NSUNST1NPRlQtQ0RPLUlO
U1RUWVBFOjANClgtTUlDUk9TT0ZULURJU0FMTE9XLUNPVU5URVI6RkFMU0UNCkJFR0lOOlZBTEFS
TQ0KREVTQ1JJUFRJT046UkVNSU5ERVINClRSSUdHRVI7UkVMQVRFRD1TVEFSVDotUFQxNU0NCkFD
VElPTjpESVNQTEFZDQpFTkQ6VkFMQVJNDQpFTkQ6VkVWRU5UDQpFTkQ6VkNBTEVOREFSDQo=
--_002_b1a01aa36e1c4b3d9969a7bbb856bd3b
理论
E-mail 消息基本上使用以下两种格式之一进行格式化。
最旧的定义为 RFC 5322
(最初是 RFC 822,但此后已更新)。
此格式不支持使用 non-ASCII 字符编码的邮件,也不支持一般 public 所谓的“附件”。
为纠正这种情况,设置的标准一般
被称为 MIME 的发明。
此集合中的标准定义:
- non-ASCII 字符编码的使用方法。
- 撰写 multi-part 条消息的方法。
两个最有趣的 MIME 标准是
RFC 2045
和 RFC 2046.
MIME纳入的标准是专门制定的
以某种方式使 MIME-encoded 的东西仍然兼容
RFC 822——除其他外,这允许不改变
MTAs
以支持新的消息格式。
实践
以各种编程语言实现的库
处理由 MIME 定义的各种位通常遵循
MIME 本身的趋势,并且能够透明地
处理“普通”RFC 822 格式的邮件和 MIME-formatted.
为了处理 MIME-formatted 消息,Go 在其标准中提供
库三个包:
还有一个,
net/textproto
,
处理MIME-style headers(也用于HTTP,
IMAP/POP3 等)。
这些软件包共同涵盖了您阅读和写入 MIME-formatted e-mail 条消息所需的大部分(或全部)内容。
解析的基本方法
解析e-mail消息的基本方法
如下:
创建bufio.Reader
的实例
来自 io.Reader
提供 e-mail 的数据
要解析的消息。
创建 net/textproto.Reader
的实例
来自上一步的 bufio.Reader
。
使用其ReadMIMEHeader()
方法读取
并解析消息的 header 块。
检查是否包含MIME-Version
RFC 2045 规定的字段指示 MIME-formatted
内容。
- 如果它包含一个,验证它的值是字面上的
“1.0”。如果不是,则这是来自
你将无法应付的未来。相应地呕吐;
否则进行下一步。
- 如果没有这样的字段,则消息是一个普通的旧 e-mail 由一个部分组成。
将其全部内容视为一个单独的 MIME-message 部分(这过于简单化了,但大多数情况下是可行的)。
如果您确认正在处理 MIME 1.0 邮件,那么
- 读取
Content-Type
header 字段然后使用
mime.ParseMediaType()
来解析它。
- 如果生成的
mediatype
值将以“multipart/”前缀开始,从字面上看,然后准备处理多个部分,这需要递归处理,因为每个部分的格式几乎与 top-level 消息——即包含 header 和 body(见下文)。
- 否则内容类型将指示某种“直接”负载(例如“text/plain”或“text/html”或其他)。
在这种情况下,这种媒体类型的一个特殊“参数”(见下文)指示用于该部分内容的字符编码,如果它是文本的话。
(另请注意,它可能是“message/rfc822”,它实际上表示有效载荷是另一条 e-mail 消息,可能需要根据与包含的规则相同的规则进行解析。)
处理“叶”部分或非multi-part 消息负载
接下来要阅读的一个重要 header 字段是 Content-Transfer-Encoding
,它定义了如何对部件进行物理编码以通过线路传输。
大多数情况下是“base64”,但也可能是“quoted-printable”。
处理 multi-part 条消息
首先,准备好正确处理“多部分”的不同方面:这些部分可能是彼此的备选方案——也就是说,程序是向用户呈现消息可能会选择其中的 任何 - 最适合用户的偏好,或者询问他们或其他东西 - 或者它们可能是实体 sort-of 相等对彼此。
前一种方案由“multipart/alternative”媒体类型表示,通常由 MUA 使用,它允许用户使用标记撰写邮件消息,然后对结果进行编码,使其包含两个备选部分——一个标记为“ text/html”和另一个标记为“text/plain”并包含已去除该标记废话的源内容。
后者由“multipart/mixed”表示,通常用于附件:使用此方案,第一部分通常(但不一定是)是消息的文本随便什么格式,其余都是附件
为了能够从消息的编码中挑选出各个部分,“multipart/whatever”媒体类型大部分时间都包含一个名为“boundary”的so-called“参数”并包含一个用于分隔各部分的唯一字符串。
mime.ParseMediaType()
函数returns将媒体类型的参数以映射的形式作为其第二个结果值。
提取“边界”媒体类型的参数后,
您可以使用它从第一步创建的 bufio.Reader
实例创建 mime/multipart.Reader
的实例。
然后您可以阅读消息部分 one-by 并对其采取行动。
请注意,如前所述,邮件部分可能具有内容类型“message/rfc822”,这意味着它包含另一个完整的邮件消息(它本身可能是 multi-part 并包含其他邮件消息等)。
到目前为止我做了什么
我使用 POP3 包来阅读我邮箱中的所有电子邮件。
我收到了来自 POP3
函数的原始电子邮件,如下例所示。 (我省略了一些信息)
问题
我遇到了从中提取信息的问题。
我使用 mail 来提取信息,但不幸的是,这个包无法从原始电子邮件中提取信息。
寻求帮助
有什么方法或软件包可以帮助我从原始电子邮件中提取信息吗?
我试过的方法
// Retrieve all the email from your mailbox
msgs, _, error := connection.ListAll()
// Convert a chunk of integer to raw email
data, _ := connection.Retr(msgs[0])
// Extract Email Address
to, _ := mail.ParseAddress(data)
我遇到的错误
panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xc0000005 code=0x0 addr=0x0 pc=0x5819ed]
原始电子邮件示例
From:
To:
Subject:
Thread-Topic:
Thread-Index: AdPgWzcFT3FjbSbUT1ycoU2ioB1bKAAAAHuA
X-MS-Exchange-MessageSentRepresentingType: 1
Date:
Message-ID:
Accept-Language: en-SG, en-US
Content-Language: en-US
X-MS-Exchange-Organization-AuthAs: Internal
X-MS-Exchange-Organization-AuthMechanism: 04
X-MS-Exchange-Organization-AuthSource:
X-MS-Has-Attach:
X-MS-Exchange-Organization-Network-Message-Id:
8c1e141b-c3ba-4471-0526-08d5b3b59967
X-MS-TNEF-Correlator:
Content-Type: multipart/alternative;
boundary="_002_b1a01aa36e1c4b3d9969a7bbb856bd3b"
MIME-Version: 1.0
--_002_b1a01aa36e1c4b3d9969a7bbb856bd3b
Content-Type: text/html; charset="utf-8"
Content-Transfer-Encoding: base64
PGh0bWwgeG1sbnM6dj0idXJuOnNjaGVtYXMtbWljcm9zb2Z0LWNvbTp2bWwiIHhtbG5zOm89InVy
bjpzY2hlbWFzLW1pY3Jvc29mdC1jb206b2ZmaWNlOm9mZmljZSIgeG1sbnM6dz0idXJuOnNjaGVt
YXMtbWljcm9zb2Z0LWNvbTpvZmZpY2U6d29yZCIgeG1sbnM6bT0iaHR0cDovL3NjaGVtYXMubWlj
cm9zb2Z0LmNvbS9vZmZpY2UvMjAwNC8xMi9vbW1sIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv
VFIvUkVDLWh0bWw0MCI+DQo8aGVhZD4NCjxtZXRhIGh0dHAtZXF1aXY9IkNvbnRlbnQtVHlwZSIg
Y29udGVudD0idGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04Ij4NCjxtZXRhIG5hbWU9IkdlbmVyYXRv
ciIgY29udGVudD0iTWljcm9zb2Z0IFdvcmQgMTUgKGZpbHRlcmVkIG1lZGl1bSkiPg0KPHN0eWxl
PjwhLS0NCi8qIEZvbnQgRGVmaW5pdGlvbnMgKi8NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6
IkNhbWJyaWEgTWF0aCI7DQoJcGFub3NlLTE6MiA0IDUgMyA1IDQgNiAzIDIgNDt9DQpAZm9udC1m
YWNlDQoJe2ZvbnQtZmFtaWx5OkRlbmdYaWFuOw0KCXBhbm9zZS0xOjIgMSA2IDAgMyAxIDEgMSAx
IDE7fQ0KQGZvbnQtZmFjZQ0KCXtmb250LWZhbWlseTpDYWxpYnJpOw0KCXBhbm9zZS0xOjIgMTUg
NSAyIDIgMiA0IDMgMiA0O30NCkBmb250LWZhY2UNCgl7Zm9udC1mYW1pbHk6IlxARGVuZ1hpYW4i
Ow0KCXBhbm9zZS0xOjIgMSA2IDAgMyAxIDEgMSAxIDE7fQ0KLyogU3R5bGUgRGVmaW5pdGlvbnMg
Ki8NCnAuTXNvTm9ybWFsLCBsaS5Nc29Ob3JtYWwsIGRpdi5Nc29Ob3JtYWwNCgl7bWFyZ2luOjBj
bTsNCgltYXJnaW4tYm90dG9tOi4wMDAxcHQ7DQoJZm9udC1zaXplOjExLjBwdDsNCglmb250LWZh
bWlseToiQ2FsaWJyaSIsc2Fucy1zZXJpZjt9DQphOmxpbmssIHNwYW4uTXNvSHlwZXJsaW5rDQoJ
e21zby1zdHlsZS1wcmlvcml0eTo5OTsNCgljb2xvcjojMDU2M0MxOw0KCXRleHQtZGVjb3JhdGlv
bjp1bmRlcmxpbmU7fQ0KYTp2aXNpdGVkLCBzcGFuLk1zb0h5cGVybGlua0ZvbGxvd2VkDQoJe21z
by1zdHlsZS1wcmlvcml0eTo5OTsNCgljb2xvcjojOTU0RjcyOw0KCXRleHQtZGVjb3JhdGlvbjp1
bmRlcmxpbmU7fQ0KcC5tc29ub3JtYWwwLCBsaS5tc29ub3JtYWwwLCBkaXYubXNvbm9ybWFsMA0K
CXttc28tc3R5bGUtbmFtZTptc29ub3JtYWw7DQoJbXNvLW1hcmdpbi10b3AtYWx0OmF1dG87DQoJ
bWFyZ2luLXJpZ2h0OjBjbTsNCgltc28tbWFyZ2luLWJvdHRvbS1hbHQ6YXV0bzsNCgltYXJnaW4t
bGVmdDowY207DQoJZm9udC1zaXplOjEyLjBwdDsNCglmb250LWZhbWlseToiVGltZXMgTmV3IFJv
bWFuIixzZXJpZjt9DQpzcGFuLkVtYWlsU3R5bGUxOA0KCXttc28tc3R5bGUtdHlwZTpwZXJzb25h
bC1jb21wb3NlOw0KCWZvbnQtZmFtaWx5OiJDYWxpYnJpIixzYW5zLXNlcmlmOw0KCWNvbG9yOndp
bmRvd3RleHQ7fQ0KLk1zb0NocERlZmF1bHQNCgl7bXNvLXN0eWxlLXR5cGU6ZXhwb3J0LW9ubHk7
DQoJZm9udC1zaXplOjEwLjBwdDsNCglmb250LWZhbWlseToiQ2FsaWJyaSIsc2Fucy1zZXJpZjt9
DQpAcGFnZSBXb3JkU2VjdGlvbjENCgl7c2l6ZTo2MTIuMHB0IDc5Mi4wcHQ7DQoJbWFyZ2luOjcy
LjBwdCA3Mi4wcHQgNzIuMHB0IDcyLjBwdDt9DQpkaXYuV29yZFNlY3Rpb24xDQoJe3BhZ2U6V29y
ZFNlY3Rpb24xO30NCi0tPjwvc3R5bGU+PCEtLVtpZiBndGUgbXNvIDldPjx4bWw+DQo8bzpzaGFw
ZWRlZmF1bHRzIHY6ZXh0PSJlZGl0IiBzcGlkbWF4PSIxMDI2IiAvPg0KPC94bWw+PCFbZW5kaWZd
LS0+PCEtLVtpZiBndGUgbXNvIDldPjx4bWw+DQo8bzpzaGFwZWxheW91dCB2OmV4dD0iZWRpdCI+
DQo8bzppZG1hcCB2OmV4dD0iZWRpdCIgZGF0YT0iMSIgLz4NCjwvbzpzaGFwZWxheW91dD48L3ht
bD48IVtlbmRpZl0tLT4NCjwvaGVhZD4NCjxib2R5IGxhbmc9IkVOLVNHIiBsaW5rPSIjMDU2M0Mx
IiB2bGluaz0iIzk1NEY3MiI+DQo8ZGl2IGNsYXNzPSJXb3JkU2VjdGlvbjEiPg0KPHAgY2xhc3M9
Ik1zb05vcm1hbCI+PG86cD4mbmJzcDs8L286cD48L3A+DQo8L2Rpdj4NCjxicj4NCjxociBhbGln
bj0ibGVmdCIgc3R5bGU9Im1hcmdpbi1sZWZ0OjA7dGV4dC1hbGlnbjpsZWZ0O3dpZHRoOjUwJTto
ZWlnaHQ6MXB4O2JhY2tncm91bmQtY29sb3I6Z3JheTtib3JkZXI6MHB4OyI+DQo8Zm9udCBzdHls
ZT0iY29sb3I6Z3JheTsiIHNpemU9Ii0xIj5UaGlzIGVtYWlsIHdhcyBzY2FubmVkIGJ5IEJpdGRl
ZmVuZGVyPC9mb250Pg0KPC9ib2R5Pg0KPC9odG1sPg0K
--_002_b1a01aa36e1c4b3d9969a7bbb856bd3b
Content-Type: text/calendar; charset="utf-8"; method=REQUEST
Content-Transfer-Encoding: base64
QkVHSU46VkNBTEVOREFSDQpNRVRIT0Q6UkVRVUVTVA0KUFJPRElEOk1pY3Jvc29mdCBFeGNoYW5n
ZSBTZXJ2ZXIgMjAxMA0KVkVSU0lPTjoyLjANCkJFR0lOOlZUSU1FWk9ORQ0KVFpJRDpTaW5nYXBv
cmUgU3RhbmRhcmQgVGltZQ0KQkVHSU46U1RBTkRBUkQNCkRUU1RBUlQ6MTYwMTAxMDFUMDAwMDAw
DQpUWk9GRlNFVEZST006KzA4MDANClRaT0ZGU0VUVE86KzA4MDANCkVORDpTVEFOREFSRA0KQkVH
SU46REFZTElHSFQNCkRUU1RBUlQ6MTYwMTAxMDFUMDAwMDAwDQpUWk9GRlNFVEZST006KzA4MDAN
ClRaT0ZGU0VUVE86KzA4MDANCkVORDpEQVlMSUdIVA0KRU5EOlZUSU1FWk9ORQ0KQkVHSU46VkVW
RU5UDQpPUkdBTklaRVI7Q049SG8gU2lldyBLZWU6TUFJTFRPOkhPX1NpZXdfS2VlQGlwaS1zaW5n
YXBvcmUub3JnDQpBVFRFTkRFRTtST0xFPVJFUS1QQVJUSUNJUEFOVDtQQVJUU1RBVD1ORUVEUy1B
Q1RJT047UlNWUD1UUlVFO0NOPUtvaCBXZWUgSG8NCiBuZzpNQUlMVE86S09IX1dlZV9Ib25nQGlw
aS1zaW5nYXBvcmUub3JnDQpERVNDUklQVElPTjtMQU5HVUFHRT1lbi1VUzpcblxuX19fX19fX19f
X19fX19fX19fX19fX19fX19fX19fX19cblRoaXMgZW1haWwNCiAgd2FzIHNjYW5uZWQgYnkgQml0
ZGVmZW5kZXJcbg0KVUlEOjA0MDAwMDAwODIwMEUwMDA3NEM1QjcxMDFBODJFMDA4MDAwMDAwMDA0
MDEzMTY0NzlFRTBEMzAxMDAwMDAwMDAwMDAwMDAwDQogMDEwMDAwMDAwMzQ5NDcwQUMzMzQ0NzM0
MDk5QzM0OEE0M0E0M0ZCREMNClNVTU1BUlk7TEFOR1VBR0U9ZW4tVVM6SFIgT3JpZW50YXRpb246
IEtvaCBXZWUgSG9uZyAoQU0gLSBEaWdpdGFsIFBsYXRmb3Jtcw0KICkNCkRUU1RBUlQ7VFpJRD1T
aW5nYXBvcmUgU3RhbmRhcmQgVGltZToyMDE4MDUwN1QxNDAwMDANCkRURU5EO1RaSUQ9U2luZ2Fw
b3JlIFN0YW5kYXJkIFRpbWU6MjAxODA1MDdUMTUzMDAwDQpDTEFTUzpQVUJMSUMNClBSSU9SSVRZ
OjUNCkRUU1RBTVA6MjAxODA1MDdUMDA1ODA2Wg0KVFJBTlNQOk9QQVFVRQ0KU1RBVFVTOkNPTkZJ
Uk1FRA0KU0VRVUVOQ0U6Mw0KTE9DQVRJT047TEFOR1VBR0U9ZW4tVVM6Q29ubmVjdGlvbg0KWC1N
SUNST1NPRlQtQ0RPLUFQUFQtU0VRVUVOQ0U6Mw0KWC1NSUNST1NPRlQtQ0RPLU9XTkVSQVBQVElE
OjEzMDY0MTMwMjYNClgtTUlDUk9TT0ZULUNETy1CVVNZU1RBVFVTOlRFTlRBVElWRQ0KWC1NSUNS
T1NPRlQtQ0RPLUlOVEVOREVEU1RBVFVTOkJVU1kNClgtTUlDUk9TT0ZULUNETy1BTExEQVlFVkVO
VDpGQUxTRQ0KWC1NSUNST1NPRlQtQ0RPLUlNUE9SVEFOQ0U6MQ0KWC1NSUNST1NPRlQtQ0RPLUlO
U1RUWVBFOjANClgtTUlDUk9TT0ZULURJU0FMTE9XLUNPVU5URVI6RkFMU0UNCkJFR0lOOlZBTEFS
TQ0KREVTQ1JJUFRJT046UkVNSU5ERVINClRSSUdHRVI7UkVMQVRFRD1TVEFSVDotUFQxNU0NCkFD
VElPTjpESVNQTEFZDQpFTkQ6VkFMQVJNDQpFTkQ6VkVWRU5UDQpFTkQ6VkNBTEVOREFSDQo=
--_002_b1a01aa36e1c4b3d9969a7bbb856bd3b
理论
E-mail 消息基本上使用以下两种格式之一进行格式化。
最旧的定义为 RFC 5322 (最初是 RFC 822,但此后已更新)。
此格式不支持使用 non-ASCII 字符编码的邮件,也不支持一般 public 所谓的“附件”。
为纠正这种情况,设置的标准一般 被称为 MIME 的发明。 此集合中的标准定义:
- non-ASCII 字符编码的使用方法。
- 撰写 multi-part 条消息的方法。
两个最有趣的 MIME 标准是 RFC 2045 和 RFC 2046.
MIME纳入的标准是专门制定的 以某种方式使 MIME-encoded 的东西仍然兼容 RFC 822——除其他外,这允许不改变 MTAs 以支持新的消息格式。
实践
以各种编程语言实现的库 处理由 MIME 定义的各种位通常遵循 MIME 本身的趋势,并且能够透明地 处理“普通”RFC 822 格式的邮件和 MIME-formatted.
为了处理 MIME-formatted 消息,Go 在其标准中提供 库三个包:
还有一个,
net/textproto
,
处理MIME-style headers(也用于HTTP,
IMAP/POP3 等)。
这些软件包共同涵盖了您阅读和写入 MIME-formatted e-mail 条消息所需的大部分(或全部)内容。
解析的基本方法
解析e-mail消息的基本方法 如下:
创建
bufio.Reader
的实例 来自io.Reader
提供 e-mail 的数据 要解析的消息。创建
net/textproto.Reader
的实例 来自上一步的bufio.Reader
。使用其
ReadMIMEHeader()
方法读取 并解析消息的 header 块。检查是否包含
MIME-Version
RFC 2045 规定的字段指示 MIME-formatted 内容。- 如果它包含一个,验证它的值是字面上的 “1.0”。如果不是,则这是来自 你将无法应付的未来。相应地呕吐; 否则进行下一步。
- 如果没有这样的字段,则消息是一个普通的旧 e-mail 由一个部分组成。 将其全部内容视为一个单独的 MIME-message 部分(这过于简单化了,但大多数情况下是可行的)。
如果您确认正在处理 MIME 1.0 邮件,那么
- 读取
Content-Type
header 字段然后使用mime.ParseMediaType()
来解析它。- 如果生成的
mediatype
值将以“multipart/”前缀开始,从字面上看,然后准备处理多个部分,这需要递归处理,因为每个部分的格式几乎与 top-level 消息——即包含 header 和 body(见下文)。 - 否则内容类型将指示某种“直接”负载(例如“text/plain”或“text/html”或其他)。 在这种情况下,这种媒体类型的一个特殊“参数”(见下文)指示用于该部分内容的字符编码,如果它是文本的话。 (另请注意,它可能是“message/rfc822”,它实际上表示有效载荷是另一条 e-mail 消息,可能需要根据与包含的规则相同的规则进行解析。)
- 如果生成的
- 读取
处理“叶”部分或非multi-part 消息负载
接下来要阅读的一个重要 header 字段是 Content-Transfer-Encoding
,它定义了如何对部件进行物理编码以通过线路传输。
大多数情况下是“base64”,但也可能是“quoted-printable”。
处理 multi-part 条消息
首先,准备好正确处理“多部分”的不同方面:这些部分可能是彼此的备选方案——也就是说,程序是向用户呈现消息可能会选择其中的 任何 - 最适合用户的偏好,或者询问他们或其他东西 - 或者它们可能是实体 sort-of 相等对彼此。 前一种方案由“multipart/alternative”媒体类型表示,通常由 MUA 使用,它允许用户使用标记撰写邮件消息,然后对结果进行编码,使其包含两个备选部分——一个标记为“ text/html”和另一个标记为“text/plain”并包含已去除该标记废话的源内容。 后者由“multipart/mixed”表示,通常用于附件:使用此方案,第一部分通常(但不一定是)是消息的文本随便什么格式,其余都是附件
为了能够从消息的编码中挑选出各个部分,“multipart/whatever”媒体类型大部分时间都包含一个名为“boundary”的so-called“参数”并包含一个用于分隔各部分的唯一字符串。
mime.ParseMediaType()
函数returns将媒体类型的参数以映射的形式作为其第二个结果值。
提取“边界”媒体类型的参数后,
您可以使用它从第一步创建的 bufio.Reader
实例创建 mime/multipart.Reader
的实例。
然后您可以阅读消息部分 one-by 并对其采取行动。
请注意,如前所述,邮件部分可能具有内容类型“message/rfc822”,这意味着它包含另一个完整的邮件消息(它本身可能是 multi-part 并包含其他邮件消息等)。