基於公網smtp協議實現郵件服務器

剛開始作郵件服務器開發,一切都是茫然的。在書上網上都很難找到一套完整的郵件服務器開發教程。在我的的摸索中碰到了不少蛋疼得問題。現終於完成了,將個人開發經驗分享給你們。web

 

 

開發環境:vs2012 mfc正則表達式

 

注意事項:編程

一、 網絡環境:windows

做爲郵件服務器,要接收來自互聯網的郵件,就得有能映射到外網的服務器。至少映射25(SMTP)端口(pop3都暫時不重要)。對於沒有外網條件的的小夥伴,推薦如下幾種方法調試:服務器

A、若是你使用model上網,查看你的電腦的外網IP。看看是否和model的一致。一致則說明你有一個公網IP。若是沒有,就致電網絡運營商,叫他給你換回公網IP,語氣必定要強硬。有了公網IP,你就能把smtp的端口映射出去。具體方法請搜索。網絡

B、對於一些校園網或大型局域網的用戶,那就有點悲劇了,基本沒法直接將端口映射出去。但能夠參考C方法。dom

C、先在的網上的網絡穿透都作的比較好,甚至能媲美公網ip的直接映射。去網上下載一些穿透軟件:花生殼之類的。都有提供內網穿透。給你們推薦個免費的網絡穿透軟件:nat123 。這軟件很好有,up主不經意的發現有大量的小學生用它在開MC的服務器。curl

D、若是你暫不須要使用外部的郵件服務器來測試你的服務器,那就在內網用其餘的郵件服務器發送至你的郵箱進行測試,要注意端口衝突。socket

二、 編寫smtp郵件服務器:學習

對於擁有外網映射的,能夠先編寫smtp 的接收服務器。這樣的好處是,能接收識別它域的不一樣類型格式的郵件,到本身發送郵件的時候,對郵件格式能有一個很好的組織。 而對於只能使用內網的用戶,建議先編寫發送端。成功進行對各個郵件服務器的發送後(這裏比較蛋疼,後面會介紹到),就能夠在編寫郵件接收端的時候用來測試。

三、 郵件服務器域名(MX)的獲取:

最開始用telnet測試163的smtp。網上搜索各大郵件服務器的stmp服務器,當初搜索出來的結果把我着實誤導了好一陣子。舉個例子把,就經常使用的企鵝郵箱,搜索出來的結果是:smtp.qq.com  25 。

因而傻傻地telnet上去helo他,他告訴我他是ehlo服務器,要登錄驗證遇到這種問題真是想哭,我一個發郵件的我給你登錄什麼啊,其餘smtp.jbjb.com郵箱也是這樣?與是想了各類奇葩的狀況與方法浪費了不少時間。最後本身去抓了一個郵件服務器的向企鵝郵箱發送的包,首先是幾個dns的包。看到有幾個dns包,本身心理頓時想到了smtp前綴的域名不是接收外域郵件的域名,看了下dns到的地址:mx1.qq.com mx2.qq.com... 原來這纔是接收郵件的服務器域名。這時候才明白本身之前掛的域名時也配置有MX地址。 總之,咱們發郵件必定要先獲取郵件接收服務器的域名。

四、 防止反垃圾郵件:

把郵件發往其餘郵件服務器,很容易被識別爲垃圾文件。新浪郵箱最討厭,直接不信任個人域名和IP地址。最初郵件格式不完善,也被企鵝斷斷續續封了幾天。就163最包容,個人郵件都慷慨地接收了。

如今發郵件,除了基本的格式,不用MINE根本不行,尤爲是當須要圖片或者附件的郵件。

五、 加密:

通常可用base64對郵件標題和內容進行加密。

六、 郵件存儲:

建議儲存爲eml格式的郵件文件,不只利於轉發或其餘應用查看,也便於以後的pop3服務器使用。

七、 web端cms

超麻煩的東西,找個模板改改吧。

 

 

 

先粗略講講SMTP協議發送郵件的過程:

直接舉個例子:

R: 220 mx.jb.com MX JB Mail Sever

S: helo wchrt.vicp.cc

R: 250 OK

S: mail from: <jb@wchrt.vicp.cc>

R: 250 OK

S: rcpt to: <414322153@qq.com>

R: 250 OK

S: data

R: 354 End data with<CR><LF>.<CR><LF>

S: mail from: jb@wchrt.vicp.cc

S: rcpt to: 414322153@qq.com

S: subject: 你好

S: 約不約?

S: <CR><LF>.<CR><LF>

R: 250 OK in queue

S: QUIT

R: 221 close

 

 

該次對話中首先咱們連接服務器後服務器給咱們返回了220 和服務器的域名信息,表示該郵件服務器正常工做,能夠提供服務。

而後咱們發送helo過去標示本身服務器的域名。

服務收到後250說明和helo成功

以後是mailfrom 說明發件人的email地址

250 ok後再rcptto 說明發送目標的Email地址

成功後,就能夠發送data命令發送郵件內容了。

Data返回的值說明郵件以<CR><LF>.<CR><LF>爲結束標記。<CR><LF>這個標示符用換行符\r\n便可。

最後返回250 標示郵件接收成功。QUIT退出。

 

如下是服務器返回的一些編號:

501 參數格式錯誤

502 命令不可實現

503錯誤的命令序列

504 命令參數不可實現

211系統狀態或系統幫助響應

214幫助信息

220 <domain>服務就緒

221 <domain>服務關閉傳輸信道

421 <domain>服務未就緒,關閉傳輸信道(當必須關閉時,此應答能夠做爲對任何命令的響應)

250要求的郵件操做完成

251用戶非本地,將轉發向<forward-path> 

450要求的郵件操做未完成,郵箱不可用(例如,郵箱忙)

550要求的郵件操做未完成,郵箱不可用(例如,郵箱未找到,或不可訪問)

451放棄要求的操做;處理過程當中出錯

551用戶非本地,請嘗試<forward-path> 

452 系統存儲不足,要求的操做未執行

552 過量的存儲分配,要求的操做未執行

553 郵箱名不可用,要求的操做未執行(例如郵箱格式錯誤)

354 開始郵件輸入,以<CRLF>.<CRLF>結束

554 操做失敗

 

具體的內容請自行搜索smtp協議

 

 

大體清楚協議後就能夠開始郵件接收端的編程,協議的細節的在調試過成功會慢慢清楚的。

服務器接收端代碼:

  1 UINT mailsever::listenthread(LPVOID Param)
  2 {
  3     int ret;
  4     SOCKET listensock;//接收郵件請求的套接字
  5     listensock=socket(AF_INET,SOCK_STREAM,0);
  6     TRACE("listensock: %d\n",listensock);
  7  
  8     sockaddr_in saddr;
  9     saddr.sin_family=AF_INET;
 10     saddr.sin_port=htons(25);//25 smtp端口
 11     saddr.sin_addr.S_un.S_addr=INADDR_ANY;
 12  
 13     ret=bind(listensock,(sockaddr *)&saddr,sizeof(sockaddr_in));
 14  
 15     ret=listen(listensock,20);//一個小服務器,暫時就只設置20的連接上限
 16  
 17     that->isseverstart=true;
 18     CString str;
 19     that->GetDlgItemTextA(IDC_LOG,str);
 20     str+="收信服務開啓\r\n";;
 21     that->SetDlgItemTextA(IDC_LOG,str);
 22  
 23     sockaddr_in newaddr;
 24     int newlen;
 25     while(1)
 26     {
 27         SOCKET newsock=accept(listensock,(sockaddr *)&newaddr,&newlen);//獲取到新郵件請求的套接字
 28         if(newsock!=SOCKET_ERROR)
 29         {
 30             AfxBeginThread(dealthread,&newsock);//開啓新線程接收郵件
 31         }
 32     }
 33     that->isseverstart=false;
 34     return 0;
 35 }
 36  
 37 static bool strcom(const char *s1,const char *s2)
 38 {
 39     int len=strlen(s2);
 40     if(strlen(s1)<len)
 41     {
 42         return false;
 43     }
 44     int py=0;
 45     for(int i=0;i<len;i++)
 46     {
 47         if(s1[i]>='A'&&s1[i]<='Z')
 48         {
 49             py=32;
 50         }
 51         else
 52         {
 53             py=0;
 54         }
 55         if(s1[i]+py!=s2[i])
 56         {
 57             return false;
 58         }
 59     }
 60  
 61     return true;
 62 }
 63  
 64 static bool isdataend(const char *ss)
 65 {
 66     int len=strlen(ss);
 67     for(int i=0;i<len-2;i++)
 68     {
 69         if(ss[i]=='\n'&&ss[i+1]=='.'&&ss[i+2]=='\r')
 70         {
 71             return true;
 72         }
 73     }
 74     return false;
 75 }
 76  
 77  
 78  
 79 UINT mailsever::dealthread(LPVOID Param)//郵件接收線程
 80 {
 81  
 82     SOCKET sock=*(SOCKET *)Param;
 83     CString sdata;
 84     char rdata[2048];
 85     int rlen;
 86      
 87     sdata.Format("220 wchrt.vicp.cc smtp WC Mail Server\r\n");
 88     send(sock,LPCTSTR(sdata),sdata.GetLength(),0);//回答本服務器狀態
 89  
 90     maildata rmail;//儲存郵件的maildata類
 91  
 92     bool ishelo=false;
 93     bool ismail=false;
 94     bool isrcpt=false;
 95     bool isdata=false;
 96     bool isenddata=false;
 97     bool istitle=false;
 98     bool isend=false;
 99     while(!isend)
100     {
101         rlen=recv(sock,rdata,2047,0);
102         if(rlen==0&&isenddata)
103         {
104             break;
105         }
106         if(rlen>2048||rlen<0)
107         {
108             continue;
109         }
110         rdata[rlen]='\0';
111         CString str;
112         CString ss;
113  
114          
115         if(strcom(rdata,"helo")||strcom(rdata,"ehlo"))//處理helo請求
116         {
117             sdata.Format("250-wchrt.vicp.cc\r\n250 OK\r\n");
118             ishelo=true;
119         }
120         else if(strcom(rdata,"mail from"))//處理郵件來源信息
121         {
122             int i=0;
123             while(i<rlen&&rdata[i]!=':')
124             {
125                 i++;
126             }
127             if(i<rlen)
128             {
129                 rmail.from.Format("%s",rdata+i);
130             }
131             ismail=true;
132             sdata.Format("250 OK\r\n");
133         }
134         else if(strcom(rdata,"rcpt to"))//處理郵件目的地信息(本地暫未按郵件用戶區分,統一接收在一塊兒)
135         {
136             int i=0;
137             while(i<rlen&&rdata[i]!=':')
138             {
139                 i++;
140             }
141             if(i<rlen)
142             {
143                 rmail.to.Format("%s",rdata+i);
144             }
145             isrcpt=true;
146             sdata.Format("250 OK\r\n");
147         }
148         else if(strcom(rdata,"data"))//處理data請求
149         {
150             if(!ismail||!isrcpt)
151             {
152                 sdata.Format("503 is not mail or rcpt\r\n");
153             }
154             else
155             {
156                 sdata.Format("354 end with <CRLF>.<CRLF>\r\n");
157                 isdata=true;
158             }
159         }
160         else if(strcom(rdata,"quit"))//處理退出服務請求
161         {
162             isend=true;
163             break;
164         }
165         else
166         {
167             if(isdata)//接收郵件內容
168             {
169                 rmail.alldata+=rdata;
170                 if(isdataend(rdata))
171                 {
172                     rmail.alldata.Replace("\r\n.\r\n","\r\n");
173                     isdata=false;
174                     sdata.Format("250 OK\r\n");
175                     isenddata=true;
176                 }
177                 else
178                 {
179                     continue;
180                 }
181             }
182             else
183             {
184                 sdata.Format("250 OK\r\n");
185             }
186         }
187         send(sock,(LPCTSTR)sdata,sdata.GetLength(),0);//返回應答
188     }
189  
190     // 開始處理並儲存接收到的郵件,處理過程詳見maildata.cpp
191     //maildata::getmailinfo(rmail);
192     CString mid;
193     mid.Format("%d",that->mailid+1);
194     if(maildata::saveeml("all",mid,rmail))
195     {
196         that->mailid++;
197         that->mailnum++;
198         CFile file;
199         if(!file.Open("mail\\info",CFile::modeReadWrite))
200         {
201             if(!file.Open("mail\\info",CFile::modeCreate|CFile::modeReadWrite))
202             {
203                 AfxMessageBox("makeinfo error");
204                 return false;
205             }
206         }
207         CString str;
208         str.Format("%d\r\n%d",that->mailid,that->mailnum);
209         file.Write(str.GetString(),str.GetLength());
210         file.Close();
211  
212         that->GetDlgItemTextA(IDC_LOG,str);
213         str+="new mail\r\n";
214         that->SetDlgItemTextA(IDC_LOG,str);
215     }
216     return 0;
217 }

 

 

郵件發送端:

 

舉個例子,咱們要往郵箱:414322153@qq.com 發送一個郵件。應遵循如下步驟:

一、提取出域名後綴:qq.com。

二、DNS查詢該域名的MX記錄。

三、根據查詢到的MX域名或IP地址連接該郵件服務器

四、使用smtp協議發送郵件

 

由於要進行DNS查詢,mfc沒有提供關於dns查詢的類。只好本身手動連接dns服務器根據dns協議查詢mx記錄。或者是調用windows自帶的nslookup來查詢dns。

爲了防止你們一些接觸太多東西,這裏就給你們講一下簡單實用nslookup查詢mx記錄的方法。等有精力再去學習dns協議。

 

cmd輸入:nslookup

將查詢設置爲mx:set q=mx

開始查詢:qq.com

 

見截圖:

 

爲方便起見,咱們就不作服務器的連通測試,直接使用第一個MX地址發送郵件。

如下是發送郵件的代碼:

 

  1 static bool getres(SOCKET sock,const char *s,const char *s2=NULL)
  2 {
  3     char *rdata=new char [2048];
  4     int rlen;
  5     CString rr,str;
  6  
  7     rlen=recv(sock,rdata,2047,0);
  8     rdata[rlen]='\0';
  9      
 10     rr.Format("%s",rdata);
 11     that->GetDlgItemTextA(IDC_LOG,str);
 12     str+=rr+"\r\n";;
 13     that->SetDlgItemTextA(IDC_LOG,str);
 14      
 15     /*TRACE("%s\n",rdata);
 16     CString ss=rdata;
 17     AfxMessageBox(ss);*/
 18  
 19     if(!strcom(rdata,s))
 20     {
 21         if(s2!=NULL)
 22         {
 23             if(!strcom(rdata,s2))
 24             {
 25                 return false;
 26             }
 27         }
 28         else
 29         {
 30             return false;
 31         }
 32     }
 33     return true;
 34 }
 35 UINT mailsever::sendthread(LPVOID Param)
 36 {
 37     CString mpath;
 38     mpath.Format("%s",Param);
 39     //AfxMessageBox(mpath);
 40     CFile file;
 41     if(!file.Open(mpath,CFile::modeRead))
 42     {
 43         return -1;
 44     }
 45  
 46     maildata rmail;
 47     char s[20480];
 48     memset(s,'\0',sizeof(s));
 49     file.Read(s,min(file.GetLength(),20470));
 50     rmail.alldata.Format(s);
 51  
 52     maildata::getmailinfo(rmail);
 53  
 54     rmail.gettoaddress();
 55  
 56     //AfxMessageBox(rmail.toaddress);
 57      
 58      
 59     //dns獲取域名mx記錄
 60     char *szDomainName= (char *)rmail.toaddress.GetString();
 61     std::vector<ULONG> veculIPList;
 62     std::vector<std::string> vecstrIPList;
 63     std::vector<std::string> vecMXList;
 64     ULONG ulTimeSpent = 0;
 65     CDNSLookup dnslookup;
 66     //使用114.114.114.144 dns服務
 67     BOOL bRet = dnslookup.DNSLookup(inet_addr("114.114.114.114"), szDomainName, &vecstrIPList, &vecMXList, 1000, &ulTimeSpent);
 68     if(!bRet)
 69     {
 70         return -1;
 71     }
 72     vecMXList[0].c_str();
 73     CString ss;
 74     ss.Format("%s",vecMXList[0].c_str());//獲取第一條記錄
 75      
 76     //AfxMessageBox(ss);
 77  
 78     SOCKET sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
 79     sockaddr_in saddr;
 80     saddr.sin_family =AF_INET;
 81     saddr.sin_port=htons(25);
 82     saddr.sin_addr.S_un.S_addr=*(u_long *)gethostbyname(vecMXList[0].c_str())->h_addr_list[0];
 83  
 84     /*CString sd=inet_ntoa(saddr.sin_addr);
 85  
 86     AfxMessageBox(sd);*/
 87  
 88     if(SOCKET_ERROR==connect(sock,(sockaddr*)&saddr,sizeof(saddr)))
 89     {
 90         return -1;
 91     }
 92  
 93      
 94  
 95     CString sdata;
 96      
 97  
 98     if(!getres(sock,"220"))
 99     {
100         return -1;
101     }
102  
103  
104     sdata.Format("HELO wchrt.vicp.cc\r\n");
105     send(sock,sdata.GetString(),sdata.GetLength(),0);
106     if(!getres(sock,"250"))
107     {
108         return -1;
109     }
110  
111  
112     sdata.Format("MAIL FROM: <%s>\r\n",rmail.from.GetString());
113     send(sock,sdata.GetString(),sdata.GetLength(),0);
114     if(!getres(sock,"250"))
115     {
116         return -1;
117     }
118  
119  
120     sdata.Format("RCPT TO: <%s>\r\n",rmail.to.GetString());
121     send(sock,sdata.GetString(),sdata.GetLength(),0);
122     if(!getres(sock,"250"))
123     {
124         return -1;
125     }
126  
127  
128  
129     sdata.Format("DATA\r\n");
130     send(sock,sdata.GetString(),sdata.GetLength(),0);
131     if(!getres(sock,"2","3"))
132     {
133         return -1;
134     }
135  
136      
137     sdata=rmail.alldata;
138  
139      
140  
141  
142     for(int i=0;i<sdata.GetLength();i+=1024)
143     {
144         /*TRACE("%d %d \n",i,sdata.GetLength());
145         char bb[1025];
146         int  j;
147         for(j=0;j<min(strlen(sdata.GetString()+i),1024);j++)
148         {
149             bb[j]=(sdata.GetString()+i)[j];
150         }bb[j]='\0';
151         TRACE("%s",bb);
152         CString ss=bb;
153         AfxMessageBox(ss);*/
154  
155         send(sock,sdata.GetString()+i,min(strlen(sdata.GetString()+i),1024),0);
156     }
157     sdata.Format("\r\n\r\n.\r\n");
158     send(sock,sdata.GetString(),sdata.GetLength(),0);
159     if(!getres(sock,"2"))
160     {
161         return -1;
162     }
163  
164  
165     sdata.Format("QUIT\r\n");
166     send(sock,sdata.GetString(),sdata.GetLength(),0);
167     if(!getres(sock,"2"))
168     {
169         return -1;
170     }
171     AfxMessageBox("ok");
172 }

 

maildata類:

 

 1 maildata.h
 2  
 3 #pragma once
 4 #define MAIL_TYPE_RECV           1
 5 #define MAIL_TYPE_SEND           2
 6 #define MAIL_TYPE_USEND          3
 7  
 8 class maildata:public CObject
 9 {
10 public:
11     maildata(void);
12      
13     ~maildata(void);
14  
15     USHORT type;
16     CString alldata;
17  
18     CString date;
19     CString from;
20     CString to;
21     CString subject;
22     CString content;
23     CString contenttype;
24  
25     CString toaddress;
26  
27     //void operator = (const maildata &);
28     void Serialize(CArchive &);
29     DECLARE_SERIAL(maildata);
30  
31  
32     static void getmailbaseinfo(maildata &);
33     static void getmailinfo(maildata &);
34     static bool setmailforsend(maildata &);
35  
36     static bool openeml(const CString,const CString,maildata &);
37     static bool saveeml(const CString,const CString,maildata &);
38     bool gettoaddress();
39 };

 

  1 maildata.cpp
  2  
  3 #include "stdafx.h"
  4 #include "maildata.h"
  5  
  6 #include "include/atlrx.h"
  7 #include "base64.h"
  8  
  9 IMPLEMENT_SERIAL(maildata,CObject,VERSIONABLE_SCHEMA|2);
 10 #ifdef _DEBUG
 11 #define new DEBUG_NEW
 12 #endif
 13  
 14 maildata::maildata(void)
 15 {
 16 }
 17  
 18  
 19 maildata::~maildata(void)
 20 {
 21 }
 22  
 23  
 24 /*void maildata::operator = (const maildata &m)
 25 {
 26 }*/
 27  
 28  
 29 void maildata::Serialize(CArchive &ar)
 30 {
 31     if(ar.IsStoring())
 32     {
 33         ar<<alldata;
 34     }
 35     else if(ar.IsLoading())
 36     {
 37         ar>>alldata;
 38     }
 39 }
 40  
 41  
 42 static bool strcom(const char *s1,const char *s2)
 43 {
 44     int len=strlen(s2);
 45     if(strlen(s1)<len)
 46     {
 47         return false;
 48     }
 49     int py=0;
 50     for(int i=0;i<len;i++)
 51     {
 52         if(s1[i]>='A'&&s1[i]<='Z')
 53         {
 54             py=32;
 55         }
 56         else
 57         {
 58             py=0;
 59         }
 60         if(s1[i]+py!=s2[i])
 61         {
 62             return false;
 63         }
 64     }
 65  
 66     return true;
 67 }
 68 static CString* strmake(const char *st,const char *ed)
 69 {
 70     if(ed<=st)
 71     {
 72         CString *str=new CString;
 73         *str="";
 74         return str;
 75     }
 76     char *data=new char[ed-st+1];
 77     int i=0;
 78     while(st+i<ed)
 79     {
 80         data[i]=st[i];
 81         i++;
 82     }
 83     data[i]='\0';
 84     CString *str;
 85     str=new CString(data);
 86     return str;
 87 }
 88 static void getcontent(CString getstr,CString &content,CString &data)//正則表達式獲取內容
 89 {
 90     CAtlRegExp<> reurl;
 91     REParseError statu=reurl.Parse(getstr);
 92     if(REPARSE_ERROR_OK!=statu)
 93     {
 94         return;
 95     }
 96     CAtlREMatchContext<> mcurl;
 97     if(!reurl.Match(content,&mcurl))
 98     {
 99         return;
100     }
101     const CAtlREMatchContext<>::RECHAR *szstart=0;
102     const CAtlREMatchContext<>::RECHAR *szend=0;
103     if(mcurl.m_uNumGroups<=0)
104     {
105         return;
106     }
107     mcurl.GetMatch(0,&szstart,&szend);
108     data=*strmake(szstart,szend);
109 }
110  
111 static void dealsbstr(CString &str)//解碼單行的=??= base64編碼字符串
112 {
113     char *s=str.GetBuffer();
114     int len=str.GetLength();
115     s[len]='\0';
116     int i=0;
117     while(i<len)
118     {
119         if(s[i]=='='&&s[i+1]=='?')
120         {
121             char rep[64];
122             int rlen=0;
123             rep[rlen++]=s[i++];
124             rep[rlen++]=s[i++];
125             while(i<len&&s[i]!='?')
126             {
127                 rep[rlen++]=s[i++];
128             }
129             rep[rlen++]=s[i++];
130             if(s[i]=='B')
131             {
132                 rep[rlen++]=s[i++];
133                 rep[rlen++]=s[i++];
134                 int j=0;
135                 char ss[64];
136                 while(i<len&&(s[i]!='?'||s[i+1]!='='))
137                 {
138                     ss[j]=s[i];
139                     rep[rlen++]=s[i++];
140                     j++;
141                 }
142                 ss[j]='\0';
143  
144                 std::string jb=base64_decode(ss);
145                 //str.Format("%s",jb.c_str());
146                  
147                 rep[rlen++]=s[i++];
148                 rep[rlen++]=s[i++];
149                 rep[rlen]='\0';
150                 str.Replace(rep,jb.c_str());
151             }
152         }
153         i++;
154     }
155 }
156  
157 void maildata::getmailbaseinfo(maildata &rmail)
158 {
159     getcontent("Date: {.*?}\r\n",rmail.alldata,rmail.date);
160     getcontent("From: {.*?}\r\n",rmail.alldata,rmail.from);
161     getcontent("To: {.*?}\r\n",rmail.alldata,rmail.to);
162     getcontent("Subject: {.*?}\r\n",rmail.alldata,rmail.subject);
163     dealsbstr(rmail.from);
164     dealsbstr(rmail.to);
165     dealsbstr(rmail.subject);
166 }
167 void maildata::getmailinfo(maildata &rmail)
168 {
169     getmailbaseinfo(rmail);
170     getcontent("Content-Type: text/plain;.*?Content-Transfer-Encoding: {.*?}\r\n",rmail.alldata,rmail.contenttype);
171     getcontent("Content-Type: text/plain;.*?\r\n\r\n{.*?}--",rmail.alldata,rmail.content);
172     //AfxMessageBox(rmail.titletype+"\r\n"+rmail.title);
173     rmail.content.Replace("\r\n","");
174     if(strcom(rmail.contenttype.GetString(),"base64"))
175     {
176         std::string ss=rmail.content.GetString();
177         ss=base64_decode(ss);
178         rmail.content=ss.c_str();
179          
180     }
181 }
182  
183 bool maildata::setmailforsend(maildata &rmail)//生成可用於發送的郵件內容
184 {
185     if(rmail.from.GetLength()<1||rmail.to.GetLength()<1||rmail.subject.GetLength()<1)
186     {
187         return false;
188     }
189  
190     rmail.type=MAIL_TYPE_USEND;
191     rmail.alldata.Format("");
192      
193     CString str;
194  
195     /*str.Format("Date: Tue, 9 Dec 2014 11:20:55 +0800\r\n",
196         rmail.from
197         );
198     rmail.alldata+=str;*/
199  
200     //格式化基本信息
201  
202     str.Format("From: %s\r\n",
203         rmail.from
204         );
205     rmail.alldata+=str;
206  
207     str.Format("To: %s\r\n",
208         rmail.to
209         );
210     rmail.alldata+=str;
211  
212  
213     str.Format("Subject: =?GBK?B?%s?=\r\n",
214         base64_encode((unsigned char *)rmail.subject.GetString(),rmail.subject.GetLength()).c_str()
215         );
216     rmail.alldata+=str;
217  
218     /*str.Format("X-Priority: 3\r\n");
219     rmail.alldata+=str;
220     str.Format("X-Mailer: wchrt's pro mail sever 1.0.0\r\n");
221     rmail.alldata+=str;
222     str.Format("X-Client-IP: 118.112.48.107\r\n");
223     rmail.alldata+=str;*/
224  
225     //加入MIME格式的郵件內容
226  
227     str.Format("Content-Type: multipart/alternative;\r\n boundary=\"--=_Part=\"\r\n");
228     rmail.alldata+=str;
229     str.Format("MIME-Version: 1.0\r\n");
230     rmail.alldata+=str;
231     str.Format("\r\nThis is a multi-part message in MIME format.\r\n\r\n----=_Part=\r\n");
232     rmail.alldata+=str;
233  
234     if(rmail.content.GetLength()>0)
235     {
236         str.Format("Content-Type: text/plain; charset=GBK\r\nContent-Transfer-Encoding: base64\r\n\r\n%s\r\n----=_Part=--\r\n",
237             base64_encode((unsigned char *)rmail.content.GetString(),rmail.content.GetLength()).c_str()
238             );
239         rmail.alldata+=str;
240     }
241  
242     //須要發送附件的話將文件讀入後添加MIME部分便可
243  
244     AfxMessageBox(rmail.alldata);
245 }
246  
247  
248 bool maildata::openeml(const CString uname,const CString mid,maildata &rmail)//打開郵件
249 {
250     CString mpath="mail";
251     mpath+="\\";
252     mpath+=uname;
253     mpath+="\\";
254     mpath+=mid+".eml";
255     CFile file;
256     if(!file.Open(mpath,CFile::modeRead))
257     {
258         return false;
259     }
260     char temp[40960];
261     UINT len=file.Read(temp,40900);
262     temp[len]='\0';
263     rmail.alldata.Format(temp);
264     //AfxMessageBox(rmail.alldata);
265     return true;
266 }
267  
268 bool maildata::saveeml(const CString uname,const CString mid,maildata &rmail)//郵件儲存
269 {
270     CString mpath="mail";
271     if(!PathIsDirectory(mpath))
272     {
273         if(!CreateDirectory(mpath,NULL))
274         {
275             return false;
276         }
277     }
278     mpath+="\\";
279     mpath+=uname;
280     if(!PathIsDirectory(mpath))
281     {
282         if(!CreateDirectory(mpath,NULL))
283         {
284             return false;
285         }
286     }
287     mpath+="\\";
288     mpath+=mid+".eml";
289  
290     CFile file;
291     if(!file.Open(mpath,CFile::modeWrite))
292     {
293         if(!file.Open(mpath,CFile::modeCreate|CFile::modeWrite))
294         {
295             return false;
296         }
297     }
298     file.Write(rmail.alldata.GetString(),rmail.alldata.GetLength());
299     file.Close();
300     return true;
301 }
302  
303 bool maildata::gettoaddress()//獲取後綴地址
304 {
305     getcontent("@{.*}",to,toaddress);
306     if(toaddress.GetLength()<1)
307     {
308         return false;
309     }
310     toaddress.Replace(" ","");
311     return true;
312 }

 

基本的smtp郵件服務器就告一段落了。剩下的就是用戶管理以及在smtp服務器基礎上製做pop3服務器以及web等。

相關文章
相關標籤/搜索