基于公网smtp协议实现邮件服务器

刚开始做邮件服务器开发,一切都是茫然的。在书上网上都很难找到一套完整的邮件服务器开发教程。在个人的摸索中碰到了很多蛋疼得问题。现终于完成了,将我的开发经验分享给大家。

 

 

开发环境:vs2012 mfc

 

注意事项:

1、 网络环境:

作为邮件服务器,要接收来自互联网的邮件,就得有能映射到外网的服务器。至少映射25(SMTP)端口(pop3都暂时不重要)。对于没有外网条件的的小伙伴,推荐以下几种方法调试:

A、如果你使用model上网,查看你的电脑的外网IP。看看是否和model的一致。一致则说明你有一个公网IP。如果没有,就致电网络运营商,叫他给你换回公网IP,语气一定要强硬。有了公网IP,你就能把smtp的端口映射出去。具体方法请搜索。

B、对于一些校园网或大型局域网的用户,那就有点悲剧了,基本无法直接将端口映射出去。但可以参考C方法。

C、先在的网上的网络穿透都做的比较好,甚至能媲美公网ip的直接映射。去网上下载一些穿透软件:花生壳之类的。都有提供内网穿透。给大家推荐个免费的网络穿透软件:nat123 。这软件很好有,up主不经意的发现有大量的小学生用它在开MC的服务器。

D、如果你暂不需要使用外部的邮件服务器来测试你的服务器,那就在内网用其他的邮件服务器发送至你的邮箱进行测试,要注意端口冲突。

2、 编写smtp邮件服务器:

对于拥有外网映射的,可以先编写smtp 的接收服务器。这样的好处是,能接收识别它域的不同类型格式的邮件,到自己发送邮件的时候,对邮件格式能有一个很好的组织。 而对于只能使用内网的用户,建议先编写发送端。成功进行对各个邮件服务器的发送后(这里比较蛋疼,后面会介绍到),就可以在编写邮件接收端的时候用来测试。

3、 邮件服务器域名(MX)的获取:

最开始用telnet测试163的smtp。网上搜索各大邮件服务器的stmp服务器,当初搜索出来的结果把我着实误导了好一阵子。举个例子把,就常用的企鹅邮箱,搜索出来的结果是:smtp.qq.com  25 。

基于公网smtp协议实现邮件服务器

于是傻傻地telnet上去helo他,他告诉我他是ehlo服务器,要登陆验证遇到这种问题真是想哭,我一个发邮件的我给你登陆什么啊,其他smtp.jbjb.com邮箱也是这样?与是想了各种奇葩的情况与方法浪费了很多时间。最后自己去抓了一个邮件服务器的向企鹅邮箱发送的包,首先是几个dns的包。看到有几个dns包,自己心理顿时想到了smtp前缀的域名不是接收外域邮件的域名,看了下dns到的地址:mx1.qq.com mx2.qq.com... 原来这才是接收邮件的服务器域名。这时候才明白自己以前挂的域名时也配置有MX地址。 总之,我们发邮件一定要先获取邮件接收服务器的域名。

4、 防止反垃圾邮件:

把邮件发往其他邮件服务器,很容易被识别为垃圾文件。新浪邮箱最讨厌,直接不信任我的域名和IP地址。最初邮件格式不完善,也被企鹅断断续续封了几天。就163最包容,我的邮件都慷慨地接收了。

现在发邮件,除了基本的格式,不用MINE根本不行,尤其是当需要图片或者附件的邮件。

5、 加密:

一般可用base64对邮件标题和内容进行加密。

6、 邮件存储:

建议储存为eml格式的邮件文件,不仅利于转发或其他应用查看,也便于之后的pop3服务器使用。

7、 web端cms

超麻烦的东西,找个模板改改吧。

 

 

 

先粗略讲讲SMTP协议发送邮件的过程:

直接举个例子:

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

S: helo wchrt.vicp.cc

R: 250 OK

S: mail from: <[email protected]>

R: 250 OK

S: rcpt to: <[email protected]>

R: 250 OK

S: data

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

S: mail from: [email protected]

S: rcpt to: [email protected]

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 }

 

 

邮件发送端:

 

举个例子,我们要往邮箱:[email protected] 发送一个邮件。应遵循以下步骤:

1、提取出域名后缀:qq.com。

2、DNS查询该域名的MX记录。

3、根据查询到的MX域名或IP地址链接该邮件服务器

4、使用smtp协议发送邮件

 

因为要进行DNS查询,mfc没有提供关于dns查询的类。只好自己手动链接dns服务器根据dns协议查询mx记录。或者是调用windows自带的nslookup来查询dns。

为了防止大家一些接触太多东西,这里就给大家讲一下简单实用nslookup查询mx记录的方法。等有精力再去学习dns协议。

 

cmd输入:nslookup

将查询设置为mx:set q=mx

开始查询:qq.com

 

见截图:

基于公网smtp协议实现邮件服务器

 

为方便起见,我们就不做服务器的连通测试,直接使用第一个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等。

 

你可能感兴趣的:(smtp)