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

开发环境: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 。

于是傻傻地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: <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协议

大致清楚协议后就可以开始邮件接收端的编程,协议的细节的在调试过成功会慢慢清楚的。

服务器接收端代码:

 UINT mailsever::listenthread(LPVOID Param)
{
int ret;
SOCKET listensock;//接收邮件请求的套接字
listensock=socket(AF_INET,SOCK_STREAM,);
TRACE("listensock: %d\n",listensock); sockaddr_in saddr;
saddr.sin_family=AF_INET;
saddr.sin_port=htons();//25 smtp端口
saddr.sin_addr.S_un.S_addr=INADDR_ANY; ret=bind(listensock,(sockaddr *)&saddr,sizeof(sockaddr_in)); ret=listen(listensock,);//一个小服务器,暂时就只设置20的链接上限 that->isseverstart=true;
CString str;
that->GetDlgItemTextA(IDC_LOG,str);
str+="收信服务开启\r\n";;
that->SetDlgItemTextA(IDC_LOG,str); sockaddr_in newaddr;
int newlen;
while()
{
SOCKET newsock=accept(listensock,(sockaddr *)&newaddr,&newlen);//获取到新邮件请求的套接字
if(newsock!=SOCKET_ERROR)
{
AfxBeginThread(dealthread,&newsock);//开启新线程接收邮件
}
}
that->isseverstart=false;
return ;
} static bool strcom(const char *s1,const char *s2)
{
int len=strlen(s2);
if(strlen(s1)<len)
{
return false;
}
int py=;
for(int i=;i<len;i++)
{
if(s1[i]>='A'&&s1[i]<='Z')
{
py=;
}
else
{
py=;
}
if(s1[i]+py!=s2[i])
{
return false;
}
} return true;
} static bool isdataend(const char *ss)
{
int len=strlen(ss);
for(int i=;i<len-;i++)
{
if(ss[i]=='\n'&&ss[i+]=='.'&&ss[i+]=='\r')
{
return true;
}
}
return false;
} UINT mailsever::dealthread(LPVOID Param)//邮件接收线程
{ SOCKET sock=*(SOCKET *)Param;
CString sdata;
char rdata[];
int rlen; sdata.Format("220 wchrt.vicp.cc smtp WC Mail Server\r\n");
send(sock,LPCTSTR(sdata),sdata.GetLength(),);//回答本服务器状态 maildata rmail;//储存邮件的maildata类 bool ishelo=false;
bool ismail=false;
bool isrcpt=false;
bool isdata=false;
bool isenddata=false;
bool istitle=false;
bool isend=false;
while(!isend)
{
rlen=recv(sock,rdata,,);
if(rlen==&&isenddata)
{
break;
}
if(rlen>||rlen<)
{
continue;
}
rdata[rlen]='\0';
CString str;
CString ss; if(strcom(rdata,"helo")||strcom(rdata,"ehlo"))//处理helo请求
{
sdata.Format("250-wchrt.vicp.cc\r\n250 OK\r\n");
ishelo=true;
}
else if(strcom(rdata,"mail from"))//处理邮件来源信息
{
int i=;
while(i<rlen&&rdata[i]!=':')
{
i++;
}
if(i<rlen)
{
rmail.from.Format("%s",rdata+i);
}
ismail=true;
sdata.Format("250 OK\r\n");
}
else if(strcom(rdata,"rcpt to"))//处理邮件目的地信息(本地暂未按邮件用户区分,统一接收在一起)
{
int i=;
while(i<rlen&&rdata[i]!=':')
{
i++;
}
if(i<rlen)
{
rmail.to.Format("%s",rdata+i);
}
isrcpt=true;
sdata.Format("250 OK\r\n");
}
else if(strcom(rdata,"data"))//处理data请求
{
if(!ismail||!isrcpt)
{
sdata.Format("503 is not mail or rcpt\r\n");
}
else
{
sdata.Format("354 end with <CRLF>.<CRLF>\r\n");
isdata=true;
}
}
else if(strcom(rdata,"quit"))//处理退出服务请求
{
isend=true;
break;
}
else
{
if(isdata)//接收邮件内容
{
rmail.alldata+=rdata;
if(isdataend(rdata))
{
rmail.alldata.Replace("\r\n.\r\n","\r\n");
isdata=false;
sdata.Format("250 OK\r\n");
isenddata=true;
}
else
{
continue;
}
}
else
{
sdata.Format("250 OK\r\n");
}
}
send(sock,(LPCTSTR)sdata,sdata.GetLength(),);//返回应答
} // 开始处理并储存接收到的邮件,处理过程详见maildata.cpp
//maildata::getmailinfo(rmail);
CString mid;
mid.Format("%d",that->mailid+);
if(maildata::saveeml("all",mid,rmail))
{
that->mailid++;
that->mailnum++;
CFile file;
if(!file.Open("mail\\info",CFile::modeReadWrite))
{
if(!file.Open("mail\\info",CFile::modeCreate|CFile::modeReadWrite))
{
AfxMessageBox("makeinfo error");
return false;
}
}
CString str;
str.Format("%d\r\n%d",that->mailid,that->mailnum);
file.Write(str.GetString(),str.GetLength());
file.Close(); that->GetDlgItemTextA(IDC_LOG,str);
str+="new mail\r\n";
that->SetDlgItemTextA(IDC_LOG,str);
}
return ;
}

邮件发送端:

举个例子,我们要往邮箱:414322153@qq.com 发送一个邮件。应遵循以下步骤:

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

见截图:

为方便起见,我们就不做服务器的连通测试,直接使用第一个MX地址发送邮件。

以下是发送邮件的代码:

 static bool getres(SOCKET sock,const char *s,const char *s2=NULL)
{
char *rdata=new char [];
int rlen;
CString rr,str; rlen=recv(sock,rdata,,);
rdata[rlen]='\0'; rr.Format("%s",rdata);
that->GetDlgItemTextA(IDC_LOG,str);
str+=rr+"\r\n";;
that->SetDlgItemTextA(IDC_LOG,str); /*TRACE("%s\n",rdata);
CString ss=rdata;
AfxMessageBox(ss);*/ if(!strcom(rdata,s))
{
if(s2!=NULL)
{
if(!strcom(rdata,s2))
{
return false;
}
}
else
{
return false;
}
}
return true;
}
UINT mailsever::sendthread(LPVOID Param)
{
CString mpath;
mpath.Format("%s",Param);
//AfxMessageBox(mpath);
CFile file;
if(!file.Open(mpath,CFile::modeRead))
{
return -;
} maildata rmail;
char s[];
memset(s,'\0',sizeof(s));
file.Read(s,min(file.GetLength(),));
rmail.alldata.Format(s); maildata::getmailinfo(rmail); rmail.gettoaddress(); //AfxMessageBox(rmail.toaddress); //dns获取域名mx记录
char *szDomainName= (char *)rmail.toaddress.GetString();
std::vector<ULONG> veculIPList;
std::vector<std::string> vecstrIPList;
std::vector<std::string> vecMXList;
ULONG ulTimeSpent = ;
CDNSLookup dnslookup;
//使用114.114.114.144 dns服务
BOOL bRet = dnslookup.DNSLookup(inet_addr("114.114.114.114"), szDomainName, &vecstrIPList, &vecMXList, , &ulTimeSpent);
if(!bRet)
{
return -;
}
vecMXList[].c_str();
CString ss;
ss.Format("%s",vecMXList[].c_str());//获取第一条记录 //AfxMessageBox(ss); SOCKET sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
sockaddr_in saddr;
saddr.sin_family =AF_INET;
saddr.sin_port=htons();
saddr.sin_addr.S_un.S_addr=*(u_long *)gethostbyname(vecMXList[].c_str())->h_addr_list[]; /*CString sd=inet_ntoa(saddr.sin_addr); AfxMessageBox(sd);*/ if(SOCKET_ERROR==connect(sock,(sockaddr*)&saddr,sizeof(saddr)))
{
return -;
} CString sdata; if(!getres(sock,""))
{
return -;
} sdata.Format("HELO wchrt.vicp.cc\r\n");
send(sock,sdata.GetString(),sdata.GetLength(),);
if(!getres(sock,""))
{
return -;
} sdata.Format("MAIL FROM: <%s>\r\n",rmail.from.GetString());
send(sock,sdata.GetString(),sdata.GetLength(),);
if(!getres(sock,""))
{
return -;
} sdata.Format("RCPT TO: <%s>\r\n",rmail.to.GetString());
send(sock,sdata.GetString(),sdata.GetLength(),);
if(!getres(sock,""))
{
return -;
} sdata.Format("DATA\r\n");
send(sock,sdata.GetString(),sdata.GetLength(),);
if(!getres(sock,"",""))
{
return -;
} sdata=rmail.alldata; for(int i=;i<sdata.GetLength();i+=)
{
/*TRACE("%d %d \n",i,sdata.GetLength());
char bb[1025];
int j;
for(j=0;j<min(strlen(sdata.GetString()+i),1024);j++)
{
bb[j]=(sdata.GetString()+i)[j];
}bb[j]='\0';
TRACE("%s",bb);
CString ss=bb;
AfxMessageBox(ss);*/ send(sock,sdata.GetString()+i,min(strlen(sdata.GetString()+i),),);
}
sdata.Format("\r\n\r\n.\r\n");
send(sock,sdata.GetString(),sdata.GetLength(),);
if(!getres(sock,""))
{
return -;
} sdata.Format("QUIT\r\n");
send(sock,sdata.GetString(),sdata.GetLength(),);
if(!getres(sock,""))
{
return -;
}
AfxMessageBox("ok");
}

maildata类:

 maildata.h

 #pragma once
#define MAIL_TYPE_RECV 1
#define MAIL_TYPE_SEND 2
#define MAIL_TYPE_USEND 3 class maildata:public CObject
{
public:
maildata(void); ~maildata(void); USHORT type;
CString alldata; CString date;
CString from;
CString to;
CString subject;
CString content;
CString contenttype; CString toaddress; //void operator = (const maildata &);
void Serialize(CArchive &);
DECLARE_SERIAL(maildata); static void getmailbaseinfo(maildata &);
static void getmailinfo(maildata &);
static bool setmailforsend(maildata &); static bool openeml(const CString,const CString,maildata &);
static bool saveeml(const CString,const CString,maildata &);
bool gettoaddress();
};
 maildata.cpp

 #include "stdafx.h"
#include "maildata.h" #include "include/atlrx.h"
#include "base64.h" IMPLEMENT_SERIAL(maildata,CObject,VERSIONABLE_SCHEMA|);
#ifdef _DEBUG
#define new DEBUG_NEW
#endif maildata::maildata(void)
{
} maildata::~maildata(void)
{
} /*void maildata::operator = (const maildata &m)
{
}*/ void maildata::Serialize(CArchive &ar)
{
if(ar.IsStoring())
{
ar<<alldata;
}
else if(ar.IsLoading())
{
ar>>alldata;
}
} static bool strcom(const char *s1,const char *s2)
{
int len=strlen(s2);
if(strlen(s1)<len)
{
return false;
}
int py=;
for(int i=;i<len;i++)
{
if(s1[i]>='A'&&s1[i]<='Z')
{
py=;
}
else
{
py=;
}
if(s1[i]+py!=s2[i])
{
return false;
}
} return true;
}
static CString* strmake(const char *st,const char *ed)
{
if(ed<=st)
{
CString *str=new CString;
*str="";
return str;
}
char *data=new char[ed-st+];
int i=;
while(st+i<ed)
{
data[i]=st[i];
i++;
}
data[i]='\0';
CString *str;
str=new CString(data);
return str;
}
static void getcontent(CString getstr,CString &content,CString &data)//正则表达式获取内容
{
CAtlRegExp<> reurl;
REParseError statu=reurl.Parse(getstr);
if(REPARSE_ERROR_OK!=statu)
{
return;
}
CAtlREMatchContext<> mcurl;
if(!reurl.Match(content,&mcurl))
{
return;
}
const CAtlREMatchContext<>::RECHAR *szstart=;
const CAtlREMatchContext<>::RECHAR *szend=;
if(mcurl.m_uNumGroups<=)
{
return;
}
mcurl.GetMatch(,&szstart,&szend);
data=*strmake(szstart,szend);
} static void dealsbstr(CString &str)//解码单行的=??= base64编码字符串
{
char *s=str.GetBuffer();
int len=str.GetLength();
s[len]='\0';
int i=;
while(i<len)
{
if(s[i]=='='&&s[i+]=='?')
{
char rep[];
int rlen=;
rep[rlen++]=s[i++];
rep[rlen++]=s[i++];
while(i<len&&s[i]!='?')
{
rep[rlen++]=s[i++];
}
rep[rlen++]=s[i++];
if(s[i]=='B')
{
rep[rlen++]=s[i++];
rep[rlen++]=s[i++];
int j=;
char ss[];
while(i<len&&(s[i]!='?'||s[i+]!='='))
{
ss[j]=s[i];
rep[rlen++]=s[i++];
j++;
}
ss[j]='\0'; std::string jb=base64_decode(ss);
//str.Format("%s",jb.c_str()); rep[rlen++]=s[i++];
rep[rlen++]=s[i++];
rep[rlen]='\0';
str.Replace(rep,jb.c_str());
}
}
i++;
}
} void maildata::getmailbaseinfo(maildata &rmail)
{
getcontent("Date: {.*?}\r\n",rmail.alldata,rmail.date);
getcontent("From: {.*?}\r\n",rmail.alldata,rmail.from);
getcontent("To: {.*?}\r\n",rmail.alldata,rmail.to);
getcontent("Subject: {.*?}\r\n",rmail.alldata,rmail.subject);
dealsbstr(rmail.from);
dealsbstr(rmail.to);
dealsbstr(rmail.subject);
}
void maildata::getmailinfo(maildata &rmail)
{
getmailbaseinfo(rmail);
getcontent("Content-Type: text/plain;.*?Content-Transfer-Encoding: {.*?}\r\n",rmail.alldata,rmail.contenttype);
getcontent("Content-Type: text/plain;.*?\r\n\r\n{.*?}--",rmail.alldata,rmail.content);
//AfxMessageBox(rmail.titletype+"\r\n"+rmail.title);
rmail.content.Replace("\r\n","");
if(strcom(rmail.contenttype.GetString(),"base64"))
{
std::string ss=rmail.content.GetString();
ss=base64_decode(ss);
rmail.content=ss.c_str(); }
} bool maildata::setmailforsend(maildata &rmail)//生成可用于发送的邮件内容
{
if(rmail.from.GetLength()<||rmail.to.GetLength()<||rmail.subject.GetLength()<)
{
return false;
} rmail.type=MAIL_TYPE_USEND;
rmail.alldata.Format(""); CString str; /*str.Format("Date: Tue, 9 Dec 2014 11:20:55 +0800\r\n",
rmail.from
);
rmail.alldata+=str;*/ //格式化基本信息 str.Format("From: %s\r\n",
rmail.from
);
rmail.alldata+=str; str.Format("To: %s\r\n",
rmail.to
);
rmail.alldata+=str; str.Format("Subject: =?GBK?B?%s?=\r\n",
base64_encode((unsigned char *)rmail.subject.GetString(),rmail.subject.GetLength()).c_str()
);
rmail.alldata+=str; /*str.Format("X-Priority: 3\r\n");
rmail.alldata+=str;
str.Format("X-Mailer: wchrt's pro mail sever 1.0.0\r\n");
rmail.alldata+=str;
str.Format("X-Client-IP: 118.112.48.107\r\n");
rmail.alldata+=str;*/ //加入MIME格式的邮件内容 str.Format("Content-Type: multipart/alternative;\r\n boundary=\"--=_Part=\"\r\n");
rmail.alldata+=str;
str.Format("MIME-Version: 1.0\r\n");
rmail.alldata+=str;
str.Format("\r\nThis is a multi-part message in MIME format.\r\n\r\n----=_Part=\r\n");
rmail.alldata+=str; if(rmail.content.GetLength()>)
{
str.Format("Content-Type: text/plain; charset=GBK\r\nContent-Transfer-Encoding: base64\r\n\r\n%s\r\n----=_Part=--\r\n",
base64_encode((unsigned char *)rmail.content.GetString(),rmail.content.GetLength()).c_str()
);
rmail.alldata+=str;
} //需要发送附件的话将文件读入后添加MIME部分即可 AfxMessageBox(rmail.alldata);
} bool maildata::openeml(const CString uname,const CString mid,maildata &rmail)//打开邮件
{
CString mpath="mail";
mpath+="\\";
mpath+=uname;
mpath+="\\";
mpath+=mid+".eml";
CFile file;
if(!file.Open(mpath,CFile::modeRead))
{
return false;
}
char temp[];
UINT len=file.Read(temp,);
temp[len]='\0';
rmail.alldata.Format(temp);
//AfxMessageBox(rmail.alldata);
return true;
} bool maildata::saveeml(const CString uname,const CString mid,maildata &rmail)//邮件储存
{
CString mpath="mail";
if(!PathIsDirectory(mpath))
{
if(!CreateDirectory(mpath,NULL))
{
return false;
}
}
mpath+="\\";
mpath+=uname;
if(!PathIsDirectory(mpath))
{
if(!CreateDirectory(mpath,NULL))
{
return false;
}
}
mpath+="\\";
mpath+=mid+".eml"; CFile file;
if(!file.Open(mpath,CFile::modeWrite))
{
if(!file.Open(mpath,CFile::modeCreate|CFile::modeWrite))
{
return false;
}
}
file.Write(rmail.alldata.GetString(),rmail.alldata.GetLength());
file.Close();
return true;
} bool maildata::gettoaddress()//获取后缀地址
{
getcontent("@{.*}",to,toaddress);
if(toaddress.GetLength()<)
{
return false;
}
toaddress.Replace(" ","");
return true;
}

基本的smtp邮件服务器就告一段落了。剩下的就是用户管理以及在smtp服务器基础上制作pop3服务器以及web等。

基于公网smtp协议实现邮件服务器的更多相关文章

  1. python3:利用smtplib库和smtp.qq.com邮件服务器发送邮件

    python3:利用smtplib库和smtp.qq.com邮件服务器发送邮件 使用qq的邮件服务器需要注意的两个地方主要是: 1.协议问题 使用465端口 SSL 协议 2.口令问题 出现SMTPA ...

  2. python开发基于SMTP协议的邮件代发服务

    写在这篇文章前照例给大家灌输点名词解释,理论知识,当然已经很熟悉的同学可以往下翻直接看干货 1. 什么是SMTP SMTP即简单传输协议(Simple Mail Transfer Protocol), ...

  3. python使用smtplib库和smtp.qq.com邮件服务器发送邮件(转)

    使用qq的邮件服务器需要注意的两个地方主要是: 1.协议问题 使用465端口 SSL 协议 2.口令问题 出现SMTPAuthenticationError 主要的原因就是口令和帐号信息不对,这里我们 ...

  4. python使用smtplib库和smtp.qq.com邮件服务器发送邮件

    使用qq的邮件服务器需要注意的两个地方主要是: 1.协议问题 使用465端口 SSL 协议 2.口令问题 出现SMTPAuthenticationError 主要的原因就是口令和帐号信息不对,这里我们 ...

  5. 使用java语言基于SMTP协议手写邮件客户端

    使用java语言基于SMTP协议手写邮件客户端 1. 说明 电子邮件是互联网上常见的应用,他是互联网早期的产品,直至今日依然受到广大用户的喜爱(在中国可能因为文化背景不同,电子邮件只在办公的时候常用) ...

  6. AspNetCore 目前不支持SMTP协议(基于开源组件开发邮件发送,它们分别是MailKit 和 FluentEmail )

    net所有的功能都要重新来一遍,集成众多类库,core任重道远,且发展且努力!! 我们都知道,很多的邮件发送都是基于这个SMTP协议,但现在的.net core对这方面还不太支持,所以我们选择这两个组 ...

  7. JAVA+PHP+阿里云组件纯手工实现POP、SMTP、IMAP开发邮件服务器(二)

    java开发邮件服务器的接收模块 用java建立socket服务端,监听端口25,实现SMTP协议.即可完成邮件服务器的接收模块. 这里要注意的是,SMTP协议其实可以分为两种.一种是你用手机.PC等 ...

  8. Windows Server 2003搭建邮件服务器

    Windows Server 2003搭建邮件服务器 由于Windows Server 2003默认是没有安装我们搭建邮件服务器所需要的POP3和SMTP服务的,因此需要我们自己来安装.方法如下: 1 ...

  9. Smtp协议与Pop3协议的简单实现

    前言 本文主要介绍smtp与pop3协议的原理,后面会附上对其的简单封装与实现. smtp协议对应的RFC文档为:RFC821 smtp协议 SMTP(Simple Mail Transfer Pro ...

随机推荐

  1. POJ2828---线段树与逆序数&&DUTOJ1210---逆序对构造排列

    来看这样一道问题:http://acm.dlut.edu.cn/problem.php?id=1210 题目大意:对于一个1-n的排列,a1,a2,a3,a4...an我们把满足i < j,ai ...

  2. windows msiexec quiet静默安装及卸载msi软件包

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoUAAAA4CAIAAAAEgBUBAAAIj0lEQVR4nO2dQXLcOAxFdbXJ0aZys6

  3. 理解Spring MVC Model Attribute和Session Attribute

    作为一名 Java Web 应用开发者,你已经快速学习了 request(HttpServletRequest)和 session(HttpSession)作用域.在设计和构建 Java Web 应用 ...

  4. java 获取系统变量(环境变量和设置变量)

    前言 环境变量这个概念不陌生, 就是操作系统的环境变量. 系统变量就是java本身维护的变量. 通过 System.getProperty 的方式获取. 对于不同的操作系统来说, 环境变量的处理可能会 ...

  5. <php>对文件的目录、属性、路径的操作

    //filetype("1.jpg");//当前路径用./或者不写:上一级用../: //echo filetype("./1.jpg"); //判断./1.j ...

  6. jQuery限制文本框只能输入正整数

    //限制键盘只能按数字键.小键盘数字键.退格键 $("#txtQty").keydown(function (e) { var code = parseInt(e.keyCode) ...

  7. Linux编程环境介绍(1) -- linux的历史

    1. linux是什么? "Hello everybody out there using minix——I'm doing a (free) operating system"  ...

  8. 【POJ2114】Boatherds 树分而治之

    做广告: #include <stdio.h> int main() { puts("转载请注明出处[vmurder]谢谢"); puts("网址:blog. ...

  9. OpenMp 基本

      OpenMp是由OpenMP Architecture Review Board牵头提出的,并已被广泛接受的,用于共享内存并行系统的多线程程序设计的一套指导性的编译处理方案(Compiler Di ...

  10. AngularJS初步

    AngularJS特点 遵循AMD规范 不需要操作节点 对于jquery,一般是利用现有完整的DOM,然后在这戏Dom的基础上进行二次调教了:而对于AngularJS等框架则是根据数据模型以及其对应用 ...