基于公网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 。
于是傻傻地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协议实现邮件服务器的更多相关文章
- python3:利用smtplib库和smtp.qq.com邮件服务器发送邮件
python3:利用smtplib库和smtp.qq.com邮件服务器发送邮件 使用qq的邮件服务器需要注意的两个地方主要是: 1.协议问题 使用465端口 SSL 协议 2.口令问题 出现SMTPA ...
- python开发基于SMTP协议的邮件代发服务
写在这篇文章前照例给大家灌输点名词解释,理论知识,当然已经很熟悉的同学可以往下翻直接看干货 1. 什么是SMTP SMTP即简单传输协议(Simple Mail Transfer Protocol), ...
- python使用smtplib库和smtp.qq.com邮件服务器发送邮件(转)
使用qq的邮件服务器需要注意的两个地方主要是: 1.协议问题 使用465端口 SSL 协议 2.口令问题 出现SMTPAuthenticationError 主要的原因就是口令和帐号信息不对,这里我们 ...
- python使用smtplib库和smtp.qq.com邮件服务器发送邮件
使用qq的邮件服务器需要注意的两个地方主要是: 1.协议问题 使用465端口 SSL 协议 2.口令问题 出现SMTPAuthenticationError 主要的原因就是口令和帐号信息不对,这里我们 ...
- 使用java语言基于SMTP协议手写邮件客户端
使用java语言基于SMTP协议手写邮件客户端 1. 说明 电子邮件是互联网上常见的应用,他是互联网早期的产品,直至今日依然受到广大用户的喜爱(在中国可能因为文化背景不同,电子邮件只在办公的时候常用) ...
- AspNetCore 目前不支持SMTP协议(基于开源组件开发邮件发送,它们分别是MailKit 和 FluentEmail )
net所有的功能都要重新来一遍,集成众多类库,core任重道远,且发展且努力!! 我们都知道,很多的邮件发送都是基于这个SMTP协议,但现在的.net core对这方面还不太支持,所以我们选择这两个组 ...
- JAVA+PHP+阿里云组件纯手工实现POP、SMTP、IMAP开发邮件服务器(二)
java开发邮件服务器的接收模块 用java建立socket服务端,监听端口25,实现SMTP协议.即可完成邮件服务器的接收模块. 这里要注意的是,SMTP协议其实可以分为两种.一种是你用手机.PC等 ...
- Windows Server 2003搭建邮件服务器
Windows Server 2003搭建邮件服务器 由于Windows Server 2003默认是没有安装我们搭建邮件服务器所需要的POP3和SMTP服务的,因此需要我们自己来安装.方法如下: 1 ...
- Smtp协议与Pop3协议的简单实现
前言 本文主要介绍smtp与pop3协议的原理,后面会附上对其的简单封装与实现. smtp协议对应的RFC文档为:RFC821 smtp协议 SMTP(Simple Mail Transfer Pro ...
随机推荐
- 【转】TI蓝牙BLE 协议栈代码学习
BLE就是低功率蓝牙.要着重了解两种设备: dual-mode双模设备:简单说就是向下兼容. single-mode单模设备:仅仅支持BLE. 关于开发主要讲的是单模设备,它可以只靠纽扣电池即可持 ...
- HttpServletRequest对象方法的用法(转)
原文地址:http://blog.csdn.net/xh16319/article/details/8450715 原文作者:ITSTAR 文章太赞,忍不住就想转..... 1. 获得客户机信息 ...
- GitHub上可能用到的开源
AGi18n :https://github.com/angelolloqui/AGi18n 可以简单地本地化你的iOS app,从代码和XIB文件中提取文本转化成可本地化的字符串,且不会改变XIB文 ...
- Laravel-表单篇-零散信息
1.asset('path'):用于引入静态文件,包括css.js.img 2.分页,调用模型的paginate(每页显示的行数)方法, 如$student = Student::paginate(2 ...
- 一起talk C栗子吧(第二十回:C语言实例--括号匹配)
各位看官们,大家好.前几回中咱们说了堆栈的原理,而且举了实际的样例进行讲解,这一回咱们说的例 子是:括号匹配. 括号匹配使用了堆栈的原理,大家能够从样例看出来.所以我们把它们放在一起.闲话 休提.言归 ...
- android布局属性具体解释
RelativeLayout用到的一些重要的属性: 1:LinearLayout ( 线性布局 ) (里面仅仅能够有一个控件,而且不能设计这个控件的位置,控件会放到左上角) 线性布局分为水平线性和垂直 ...
- VMware vSphere 5.5的12个更新亮点(1)
[IT专家网虚拟化]在VMworld 2013大会上发布的VMware vSphere 5.5版本提供的增强和改进,横跨从hypervisor到管理整个堆栈,提升了VMware的性能.可伸缩性和可用性 ...
- iCIBA简单案例
效果图: 代码: <!DOCTYPE html><html> <head> <meta charset="utf-8" /> < ...
- C#调用C++的DLL 数据类型转换
/C++中的DLL函数原型为 //extern "C" __declspec(dllexport) bool 方法名一(const char* 变量名1, unsig ...
- ORA-00257: archiver error. Connect internal only, until freed 错误的处理方法
转帖:原文地址http://blog.csdn.net/panys/article/details/3838846 archive log 日志已满ORA-00257: archiver error. ...