文档章节

基于gmime2.0库的邮件解码程序实现

brucema
 brucema
发布于 2012/04/28 11:07
字数 1450
阅读 1638
收藏 2

Gmime 库是一套非常强大MIME(Multipurpose Internet Mail Extension)工具库,用来创建、编辑、分解MIME消息和结构。Gmime本身基于Glib2.0的Gobject,具有良好的扩展性。GMIME遵循GPL许可,源代码公开。本文通过一个最简单的程序,讲解了如何利用该库去实现对一封邮件进行内容还原。

 

一、测试邮件生成

在outlook收件箱中新建一邮件,仅包含正文内容,没有附件等其他东西。

标题为: test mail

发件人为: sdx@prospect.com.cn

收件人为:sdx@prospect.com.cn

正文内容是:

hello billy.

 

这是一封测试信.

 

石冬雪

然后,另存为testmail.eml。这就是我们将要分析的邮件,通过INTERNET捕包或者邮件代理程序接收到的邮件原始信息跟它是一样的。它的内容如下:

From: "billy shi" <sdx@prospect.com.cn>

To: "sdx@prospect.com.cn"

Subject: test mail

Date: Mon, 9 May 2005 15:18:53 +0800

MIME-Version: 1.0

Content-Type: multipart/alternative;

    boundary="----=_NextPart_000_000C_01C554AA.7B713F40"

X-Priority: 3

X-MSMail-Priority:

Normal

X-Unsent: 1

X-MimeOLE: Produced By Microsoft MimeOLE V6.00.2800.1441

 

This is a multi-part message in MIME format.

 

------=_NextPart_000_000C_01C554AA.7B713F40

Content-Type: text/plain;

    charset="gb2312"

Content-Transfer-Encoding: base64

 

aGVsbG8gYmlsbHkuDQoNCtXiysfSu7fisuLK1NDFLg0KDQrKr7as0ak=

 

------=_NextPart_000_000C_01C554AA.7B713F40

Content-Type: text/html;

    charset="gb2312"

Content-Transfer-Encoding: base64

 

PCFET0NUWVBFIEhUTUwgUFVCTElDICItLy9XM0MvL0RURCBIVE1MIDQuMCBUcmFuc2l0aW9uYWwv

L0VOIj4NCjxIVE1MPjxIRUFEPg0KPE1FVEEgaHR0cC1lcXVpdj1Db250ZW50LVR5cGUgY29udGVu

dD0idGV4dC9odG1sOyBjaGFyc2V0PWdiMjMxMiI+DQo8TUVUQSBjb250ZW50PSJNU0hUTUwgNi4w

MC4yODAwLjE0OTgiIG5hbWU9R0VORVJBVE9SPg0KPFNUWUxFPjwvU1RZTEU+DQo8L0hFQUQ+DQo8

Qk9EWSBiZ0NvbG9yPSNmZmZmZmY+DQo8RElWPjxGT05UIHNpemU9Mj5oZWxsbyBiaWxseS48L0ZP

TlQ+PC9ESVY+DQo8RElWPjxGT05UIHNpemU9Mj48L0ZPTlQ+Jm5ic3A7PC9ESVY+DQo8RElWPjxG

T05UIHNpemU9Mj7V4srH0ru34rLiytTQxS48L0ZPTlQ+PC9ESVY+DQo8RElWPjxGT05UIHNpemU9

Mj48L0ZPTlQ+Jm5ic3A7PC9ESVY+DQo8RElWPjxGT05UIHNpemU9Mj7Kr7as0ak8L0ZPTlQ+PC9E

SVY+PC9CT0RZPjwvSFRNTD4NCg==

 

------=_NextPart_000_000C_01C554AA.7B713F40--

我们看到,经编码过之后,邮件标题和发信人/收信人还可读,但邮件内容变得不可读。

二、邮件原始结构分析

l         此邮件是一个混合体,混合的两部分是等价的,其中一部分是采用PLAIN明文方式,另一部分是采用HTML网页方式,任一部分内容分析出来都可以;

l         每部分都采用了BASE64来编码;

l         各部分均采使用了gb2312字符集;

l         各部分的分界线为:”----=_NextPart_000_000C_01C554AA.7B713F40”;

另外,将该邮件上传到linux服务器可看出,它每行是以\r\n结尾的,跟LINUX下的邮件内容有区别,需要对CRLF进行特别处理。

三、Gmime2.0简介

a)         框架

                         i.              GMime Streams

GMimeContentType

    GMimeDisposition

    GMimeHeader

    GMimeParam

    GObject

        GMimeDataWrapper

        GMimeObject

            GMimeMessage

            GMimeMessagePart

            GMimeMessagePartial

            GMimeMultipart

                GMimeMultipartEncrypted

                GMimeMultipartSigned

            GMimePart

        GMimeParser

        GMimeStream

            GMimeStreamBuffer

            GMimeStreamCat

            GMimeStreamFile

            GMimeStreamFilter

            GMimeStreamFs

            GMimeStreamMem

            GMimeStreamMmap

            GMimeStreamNull

        GMimeFilter

            GMimeFilterBasic

            GMimeFilterBest

            GMimeFilterCharset

            GMimeFilterCRLF

            GMimeFilterFrom

            GMimeFilterHTML

            GMimeFilterMd5

            GMimeFilterStrip

            GMimeFilterYenc

        GMimeCipherContext

            GMimeGpgContext

        GMimeSession

    InternetAddress

 

 

       各对象细节详见《GMime Reference Manual》。

四、解码程序开发

a)         例程

      1 #include <stdio.h>

      2 #include <gmime/gmime.h>

      3 void Walk(GMimeObject* pPart,int nDepth)

      4 {

      5         printf("Geting %d part content type...\n",nDepth);

      6         const GMimeContentType* pContentType = g_mime_object_get_content_type(pPart) ;

      7         char* szContentType = g_mime_content_type_to_string(pContentType);

      8         printf("The content type is: %s or direct get from the object(%s/%s)\n",szContentType,pContentType->type,pCont        entType->subtype);

      9         g_free(szContentType);

     10

     11         char* szObject = g_mime_object_to_string(pPart);

     12 //      printf("The object is :%s\n",szObject);

     13         g_free(szObject);

     14

     15         const char* szHeader = g_mime_object_get_headers(pPart);

     16         printf("The object's header is:%s\n",szHeader);

     17         const char* szContentId = g_mime_object_get_content_id (pPart);

     18         printf("The object's content id is:%s\n",szContentId);

     19

     20         if(GMIME_IS_MULTIPART(pPart))

     21         {

     22                 GMimeMultipart* pMultipart = GMIME_MULTIPART(pPart);

     23                 printf("The GMimeObject can convert to GMimeMultiPart object...\n");

     24                 printf("The multipart preface is: %s\n",g_mime_multipart_get_preface (GMIME_MULTIPART(pPart)));

     25                 printf("The multipart number is %d\n",g_mime_multipart_get_number (pMultipart));

     26                 printf("The multipart boundary is:%s\n",g_mime_multipart_get_boundary (pMultipart));

     27

     28                 GList* pSubParts =  pMultipart->subparts;

     29

     30                 if(pSubParts==NULL)

     31                         printf("The multipart has no subparts, wrong mail????\n");

     32                 int j=0;

     33                 while(pSubParts)

     34                 {

     35                         pSubParts = pSubParts->next;

     36                         printf("multi part no%d\n",j++);

     37                 }

     38

     39         }

     40 }

     41 void Analyze(GMimeMessage* pMessage)

     42 {

     43         printf("analyze the message begin...\n");

44         Walk(pMessage->mime_part,0);

     45 }

     46 int main(int argc,char** argv)

     47 {

     48         g_mime_init(0);

     49         if(argc<2)

     50         {

     51                 printf("error open file to parser. hello <file>\n");

     52                 return 0;

     53         }

     54         printf("hello, gmime! please\n");

     55

     56         FILE* fp = fopen(argv[1],"rb");

     57         GMimeStream* pStream = g_mime_stream_file_new(fp);

     58

     59

     60         printf("[main] g_mime_stream_file_new success!\n");

     61

     62         GMimeFilter* pCrlfFilter = g_mime_filter_crlf_new (GMIME_FILTER_CRLF_DECODE,GMIME_FILTER_CRLF_MODE_CRLF_ONLY);

     63         printf("[main] new crlf filter success!\n");

     64

     65         GMimeStream* pFilterStream = g_mime_stream_filter_new_with_stream (pStream);

     66         printf("[main] create filter stream with file stream success!\n");

     67         printf("unref the stream object.\n");

     68         g_mime_stream_unref(pStream);

     69

     70         g_mime_stream_filter_add (GMIME_STREAM_FILTER (pFilterStream), pCrlfFilter);

     71         g_object_unref (pCrlfFilter);

     72         printf("[main] add crlf filter to decode success!\n");

     73

     74         GMimeParser* pParser = g_mime_parser_new();

     75         if(!pParser)

     76         {

     77                 printf("error new parser.\n");

     78         }

     79         printf("new parser success!\n");

     80

     81

     82

     83         g_mime_parser_init_with_stream(pParser,pFilterStream);

     84         GMimeMessage* pMessage = g_mime_parser_construct_message(pParser);

     85         if(!pMessage)

     86         {

     87                 printf("error construct the message!\n");

    88                 return 0;

     89         }

     90         printf("construct message with filter stream success!\n");

     91

     92         printf("unref the filter stream.\n");

     93         g_mime_stream_unref(pFilterStream);

     94         printf("unref the parser object.\n");

     95         g_object_unref(pParser);

     96

     97         printf("sender:%s\n",g_mime_message_get_sender(pMessage));

     98         printf("rcpt to:%s\n",g_mime_message_get_reply_to (pMessage));

     99         printf("subject:%s\n",g_mime_message_get_subject (pMessage));

    100         gboolean is_html;

    101         printf("body:%s\n",g_mime_message_get_body (pMessage,true,&is_html));

    102

    103         Analyze(pMessage);

    104         printf("unref the pMessage object.\n");

    105         g_object_unref(GMIME_OBJECT(pMessage));

    106         return 1;

    107 }

 

b)        编译方法:

c++ `pkg-config --cflags --libs gmime-2.0` hello.cpp -o hello

c)        代码介绍

第2行,必须包含<gmime/gmime.h>,才能使用GMIME库的接口。

第46行,main开始

该程序要求带一个参数,作为要分析的邮件原始文件名。

48行,g_mime_init(0) 必须在所有GMIME函数调用之前调用。

57行,创建一个基于文件的流对象,流对象见上述。

62行,创建一个CRLF过滤器,过滤器介绍见前述。一般而言,MTA之间的通信每行都是以\n结尾的,但因为我们要处理以CRLF结尾的邮件体,所以必须附加一个CRLF过滤器来处理\r\n.

65行,根据初始文件流和过滤器创建一个具备过滤功能的流对象。

74行,创建一个MIME解析器,分析器可对一封邮件进行解析,生成消息对象。在消息对象对邮件消息进行结构化的存储。通过消息对象可以遍历邮件各部分内容。

83行,根据输入流对象对MIME解析器进行初始化。

84行,利用MIME解析器生成消息对象。

97-99行,获取消息对象中的“发信人”、“收信人”和“主题”。

101行,从消息对象中获取邮件体。

28行, 对一个混合型邮件体,获取其混合对象链表。利用该链表对象可遍历混合体中的各部分。

33-37行,遍历组成混合体的各部分邮件体对象

© 著作权归作者所有

上一篇: pkg-config用法
下一篇: B+树与文件系统
brucema
粉丝 12
博文 130
码字总数 125674
作品 0
深圳
高级程序员
私信 提问
FFmpeg编写一个简单播放器 --开篇

FFMPEG是一个很好的库,可以用来创建视频应用或者生成特定的工具。FFMPEG几乎为你把所有的繁重工作都做了,比如解码、编码、复用和解复用。这使得多媒体应用程序变得容易编写。它是一个简单的...

GuoKai
2012/09/19
367
0
15个PHP库,你值得拥有!(下)

在PHP程序员应该知道的15个库(上)一文中,小编为大家介绍了Mink、Geocoder、Ratchet等8个有用的PHP库,接下来将继续介绍余下的几个PHP库,欢迎大家品鉴! 9. PHP-CPP PHP-CPP基本上属于一个...

Miss_Hello_World
2015/09/06
57
0
pythond的常用库有哪些

我自己常用的python库(不断更新) 不断更新,便于学习过程中不断总结。 排序不分优先级. 1.os 和操作系统有关 2.time 与时间有关 3.pcap 抓包 4.dpkt 解包和组包 5.pymssql 进行mssql数据库...

铁扇公主1
2017/03/16
647
2
高性能C++的UDP网络库--Raknet

Raknet是一个基于UDP网络传输协议的C++网络库,允许程序员在他们自己的程序中实现高效的网络传输服务。通常情况下用于游戏,但也可以用于其它项目。 Raknet有以下好处: 高性能 在同一台计算...

匿名
2010/01/13
27.8K
1
用户空间文件系统--fufs

FUFS 是一款基于linux c语言版fuse 开发的用户空间文件系统,实现了在linux 中对新浪微盘的基本操作。文件系统实现了对新浪微盘API的封装,当文件系统挂载到用户linux 的某个文件夹下,用户只...

hello_win
2012/08/09
4.2K
0

没有更多内容

加载失败,请刷新页面

加载更多

java 函数式编程

@FunctionalInterface public interface Handler { public abstract void handler1(); public default void defaultMethod(){ System.out.println("this is default method"); } // 静态方法......

漫步行者
18分钟前
3
0
Oh my zsh安装配置

详情参考: https://www.cnblogs.com/dylancao/p/11856854.html

tahiti_aa
21分钟前
3
0
spring boot 中jpa 使用sqlite

maven 依赖 hibernate新版本中去掉了sqlite的支持,如要使用需要导入jar包 <dependency> <groupId>com.zsoltfabok</groupId> <artifactId>sqlite-dialect<......

MeiJM
23分钟前
4
0
好程序员web前端分享JavaScript到底是什么?特点有哪些?

  好程序员web前端分享JavaScript到底是什么?特点有哪些?这也是成为web前端工程师必学的内容。今天为大家分享了这篇关于JavaScript的文章,我们一起来看看。   一、JavaScript是什么?...

好程序员官网
30分钟前
5
0
JAVA--高级基础开发

//定义两个线程,一个线程输出偶数,一个线程输出奇数,并且是交替输出 public class Test08 { public static void main(String[]args){ //创建当前类的对象 Life num = new L...

李文杰-yaya
47分钟前
19
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部