深入Lumisoft.NET组件与.NET API实现邮件发送功能的对比分析
我在另一篇文章《深入lumisoft.net实现邮件发送功能的方法详解》有大致对这个lumisoft.net组件的使用进行了介绍,当然lumisoft.net组件除了提供邮件发送功能外,还提供了邮件接收等功能的处理(包括基于pop3协议和imap协议),而.net则除了提供smtp协议功能外,则没有提供pop3协议处理的相关类库,因此收取邮件这需要自己进行封装(需要也可以参考codeproject.com上的相关文章)。
1、.net的邮件发送功能实现
.net本身封装了一个smtpclient类以及相关的邮件对象类,这样利用这些类库,也可以方便实现邮件的发送功能的了。
如添加发送人地址,抄送地址,以及暗送地址(多个地址用逗号分开)代码如下。
string toemails = mailinfo.toemail;
string bcc = "";
mailinfo.recipientbcc.foreach(obj => bcc += string.format("{0},", obj));
bcc = bcc.trim(',');
string cc = "";
mailinfo.recipientcc.foreach(obj => cc += string.format("{0},", obj));
cc = cc.trim(',');
mailmessage mail = new mailmessage(settinginfo.mailfrom, toemails);
if (!string.isnullorempty(bcc))
{
mail.bcc.add(bcc);
}
if (!string.isnullorempty(cc))
{
mail.cc.add(cc);
}
.net的附件和嵌入式资源由对象attachment和linkedresource进行管理,他们的利用代码如下所示:
//附件
foreach (string filename in mailinfo.attachments)
{
mail.attachments.add(new attachment(filename));
}
//嵌入资源
alternateview view = alternateview.createalternateviewfromstring(mailinfo.body, encoding.utf8, mediatypenames.text.html);
foreach (linkedattachementinfo link in mailinfo.embedobjects)
{
linkedresource resource = new linkedresource(link.stream, link.mimetype);
resource.contentid = link.contentid;
view.linkedresources.add(resource);
}
mail.alternateviews.add(view);
发送邮件的其他部分代码如下所示
mail.isbodyhtml = mailinfo.isbodyhtml;
mail.bodyencoding = encoding.utf8;
mail.subject = mailinfo.subject;
mail.subjectencoding = encoding.utf8;
//发送账户设置信息
smtpclient client = new smtpclient();
client.host = settinginfo.smtpserver;
client.port = settinginfo.smptport;
client.usedefaultcredentials = false;
client.deliverymethod = smtpdeliverymethod.network;
client.credentials = new networkcredential(settinginfo.smtpuser, settinginfo.smtppass);
bool success = false;
try
{
client.send(mail);
success = true;
}
catch (exception ex)
{
logtexthelper.error(ex);
//throw;
}
上面利用.net的smtpclient发送邮件操作的完整代码如下:
/// <summary>
/// 发送外部邮件(系统配置,系统邮件)
/// </summary>
/// <param name="mailinfo">发送邮件信息</param>
/// <returns></returns>
public commonresult send(mailinfo mailinfo)
{
commonresult result = new commonresult();
try
{
appconfig config = new appconfig();
string maildomain = config.appconfigget("maildomain");
string mailusername = config.appconfigget("mailusername");
string mailpassword = config.appconfigget("mailpassword");
string mailport = config.appconfigget("mailport");
string mailfrom = config.appconfigget("mailfrom");
int port = 25;
int.tryparse(mailport, out port);
smtpsettinginfo settinginfo = new smtpsettinginfo(maildomain, port,
mailusername, mailpassword, mailfrom);
result.success = privatesendemail(mailinfo, settinginfo);
}
catch (exception ex)
{
result.errormessage = ex.message;
throw;
}
return result;
}
/// <summary>
/// 通用发送邮件操作
/// </summary>
private static bool privatesendemail(mailinfo mailinfo, smtpsettinginfo settinginfo)
{
string toemails = mailinfo.toemail;
string bcc = "";
mailinfo.recipientbcc.foreach(obj => bcc += string.format("{0},", obj));
bcc = bcc.trim(',');
string cc = "";
mailinfo.recipientcc.foreach(obj => cc += string.format("{0},", obj));
cc = cc.trim(',');
mailmessage mail = new mailmessage(settinginfo.mailfrom, toemails);
if (!string.isnullorempty(bcc))
{
mail.bcc.add(bcc);
}
if (!string.isnullorempty(cc))
{
mail.cc.add(cc);
}
//附件
foreach (string filename in mailinfo.attachments)
{
mail.attachments.add(new attachment(filename));
}
//嵌入资源
alternateview view = alternateview.createalternateviewfromstring(mailinfo.body, encoding.utf8, mediatypenames.text.html);
foreach (linkedattachementinfo link in mailinfo.embedobjects)
{
linkedresource resource = new linkedresource(link.stream, link.mimetype);
resource.contentid = link.contentid;
view.linkedresources.add(resource);
}
mail.alternateviews.add(view);
mail.isbodyhtml = mailinfo.isbodyhtml;
mail.bodyencoding = encoding.utf8;
mail.subject = mailinfo.subject;
mail.subjectencoding = encoding.utf8;
//发送账户设置信息
smtpclient client = new smtpclient();
client.host = settinginfo.smtpserver;
client.port = settinginfo.smptport;
client.usedefaultcredentials = false;
client.deliverymethod = smtpdeliverymethod.network;
client.credentials = new networkcredential(settinginfo.smtpuser, settinginfo.smtppass);
bool success = false;
try
{
client.send(mail);
success = true;
}
catch (exception ex)
{
logtexthelper.error(ex);
//throw;
}
string message = string.format("发送给【{0}】的邮件“{1}”,{2},时间:{3}",
mailinfo.toemail[0], mailinfo.subject, success ? "发送成功" : "发送失败", datetime.now);
logtexthelper.info(message);
return success;
}
2、基于lumisoft.net组件的邮件发送功能实现
基于lumisoft.net组件的邮件发送,也是一种很常用的,因为这个开源组件非常强大,经常可以在一些程序中被使用。
这个发送邮件的功能主要是利用smtp_client类来实现的,如下代码所示。注意其中的authenticate函数已经被舍弃,可以使用auth方法进行验证。但是函数参数有所不同,根据验证对象,使用不同的验证方式,一般选择auth_sasl_client_plain对象即可。
public bool send()
{
bool sended = false;
using (smtp_client client = new smtp_client())
{
client.connect(smtpserver, smtpport, smtpusessl);
client.ehlohelo(smtpserver);
var authhh = new auth_sasl_client_plain(username, password);
client.auth(authhh);
//client.authenticate(username, password);
//string text = client.greetingtext;
client.mailfrom(from, -1);
foreach (string address in tolist.keys)
{
client.rcptto(address);
}
//采用mail_message类型的stream
mail_message m = create_plaintext_html_attachment_image(tolist, cclist, from, fromdisplay, subject, body, attachments);
using (memorystream stream = new memorystream())
{
m.tostream(stream, new mime_encoding_encodedword(mime_encodedwordencoding.q, encoding.utf8), encoding.utf8);
stream.position = 0;
client.sendmessage(stream);
sended = true;
}
if (m != null)
{
m.dispose();
}
client.disconnect();
}
return sended;
}
构造用于smtp发送的数据,可以使用mail_message 对象,也可以使用mime对象,虽然读都可以实现发送功能,不过mime对象是舍弃的对象了。
构造mail_message对象后,创建用于发送的格式要转换为stream对象。转换为发送的stream操作如下所示。
using (memorystream stream = new memorystream())
{
m.tostream(stream, new mime_encoding_encodedword(mime_encodedwordencoding.q, encoding.utf8), encoding.utf8);
stream.position = 0;
client.sendmessage(stream);
sended = true;
}
构造mail_message格式的邮件操作如下所示。
private mail_message create_plaintext_html_attachment_image(dictionary<string,string> tomails, dictionary<string, string> ccmails, string mailfrom, string mailfromdisplay,
string subject, string body, dictionary<string, string> attachments, string notifyemail = "", string plainttexttips = "")
{
mail_message msg = new mail_message();
msg.mimeversion = "1.0";
msg.messageid = mime_utils.createmessageid();
msg.date = datetime.now;
msg.subject = subject;
msg.from = new mail_t_mailboxlist();
msg.from.add(new mail_t_mailbox(mailfromdisplay, mailfrom));
msg.to = new mail_t_addresslist();
foreach (string address in tomails.keys)
{
string displayname = tomails[address];
msg.to.add(new mail_t_mailbox(displayname, address));
}
msg.cc = new mail_t_addresslist();
foreach (string address in ccmails.keys)
{
string displayname = ccmails[address];
msg.cc.add(new mail_t_mailbox(displayname, address));
}
//设置回执通知
if (!string.isnullorempty(notifyemail) && validateutil.isemail(notifyemail))
{
msg.dispositionnotificationto.add(new mail_t_mailbox(notifyemail, notifyemail));
}
#region myregion
//--- multipart/mixed -----------------------------------
mime_h_contenttype contenttype_multipartmixed = new mime_h_contenttype(mime_mediatypes.multipart.mixed);
contenttype_multipartmixed.param_boundary = guid.newguid().tostring().replace('-', '.');
mime_b_multipartmixed multipartmixed = new mime_b_multipartmixed(contenttype_multipartmixed);
msg.body = multipartmixed;
//--- multipart/alternative -----------------------------
mime_entity entity_multipartalternative = new mime_entity();
mime_h_contenttype contenttype_multipartalternative = new mime_h_contenttype(mime_mediatypes.multipart.alternative);
contenttype_multipartalternative.param_boundary = guid.newguid().tostring().replace('-', '.');
mime_b_multipartalternative multipartalternative = new mime_b_multipartalternative(contenttype_multipartalternative);
entity_multipartalternative.body = multipartalternative;
multipartmixed.bodyparts.add(entity_multipartalternative);
//--- text/plain ----------------------------------------
mime_entity entity_text_plain = new mime_entity();
mime_b_text text_plain = new mime_b_text(mime_mediatypes.text.plain);
entity_text_plain.body = text_plain;
//普通文本邮件内容,如果对方的收件客户端不支持html,这是必需的
string plaintextbody = "如果你邮件客户端不支持html格式,或者你切换到“普通文本”视图,将看到此内容";
if (!string.isnullorempty(plainttexttips))
{
plaintextbody = plainttexttips;
}
text_plain.settext(mime_transferencodings.quotedprintable, encoding.utf8, plaintextbody);
multipartalternative.bodyparts.add(entity_text_plain);
//--- text/html -----------------------------------------
string htmltext = body;//"<html>这是一份测试邮件,<img src=\"cid:test.jpg\">来自<font color=red><b>lumisoft.net</b></font></html>";
mime_entity entity_text_html = new mime_entity();
mime_b_text text_html = new mime_b_text(mime_mediatypes.text.html);
entity_text_html.body = text_html;
text_html.settext(mime_transferencodings.quotedprintable, encoding.utf8, htmltext);
multipartalternative.bodyparts.add(entity_text_html);
//--- application/octet-stream -------------------------
webclient client = new webclient();
foreach (string attach in attachments.keys)
{
try
{
byte[] bytes = client.downloaddata(attach);
using (memorystream stream = new memorystream(bytes))
{
multipartmixed.bodyparts.add(mail_message.createattachment(stream, attachments[attach]));
}
}
catch (exception ex)
{
logtexthelper.error(ex);
}
}
#endregion
return msg;
}
而构造mime格式的操作如下所示。
private mime create_html_attachment_image(string mailto, string mailfrom, string mailfromdisplay,
string subject, string body, list<string> attachments, dictionary<string, string> embedimages, string notifyemail = "", string plainttexttips = "",
string replyemail = "")
{
mime m = new mime();
mimeentity mainentity = m.mainentity;
mainentity.from = new addresslist();
mainentity.from.add(new mailboxaddress(mailfromdisplay, mailfrom));
mainentity.to = new addresslist();
mainentity.to.add(new mailboxaddress(mailto, mailto));
mainentity.subject = subject;
mainentity.contenttype = mediatype_enum.multipart_mixed;
//设置回执通知
if (!string.isnullorempty(notifyemail) && validateutil.isemail(notifyemail))
{
mainentity.dsn = notifyemail;
}
//设置统一回复地址
if (!string.isnullorempty(replyemail) && validateutil.isemail(replyemail))
{
mainentity.replyto = new addresslist();
mainentity.replyto.add(new mailboxaddress(replyemail, replyemail));
}
mimeentity textentity = mainentity.childentities.add();
textentity.contenttype = mediatype_enum.text_html;
textentity.contenttransferencoding = contenttransferencoding_enum.quotedprintable;
textentity.datatext = body;
//附件
foreach (string attach in attachments)
{
mimeentity attachmententity = mainentity.childentities.add();
attachmententity.contenttype = mediatype_enum.application_octet_stream;
attachmententity.contentdisposition = contentdisposition_enum.attachment;
attachmententity.contenttransferencoding = contenttransferencoding_enum.base64;
fileinfo file = new fileinfo(attach);
attachmententity.contentdisposition_filename = file.name;
attachmententity.datafromfile(attach);
}
//嵌入图片
foreach (string key in embedimages.keys)
{
mimeentity attachmententity = mainentity.childentities.add();
attachmententity.contenttype = mediatype_enum.application_octet_stream;
attachmententity.contentdisposition = contentdisposition_enum.inline;
attachmententity.contenttransferencoding = contenttransferencoding_enum.base64;
string imagefile = embedimages[key];
fileinfo file = new fileinfo(imagefile);
attachmententity.contentdisposition_filename = file.name;
//string displayname = path.getfilenamewithoutextension(filename);
attachmententity.contentid = key;//bytestools.bytestohex(encoding.default.getbytes(filename));
attachmententity.datafromfile(imagefile);
}
return m;
}
综合以上两者的发送功能,都可以实现邮件的发送操作,如下界面是发送邮件界面。
3、lumisoft.net存储eml邮件文件以及发送eml文件操作
除了上面的发送普通邮件,lumisoft还支持吧邮件序列号存储到文件(.eml邮件文件)里面,然后也可以通过把文件读取到流里面,进行发送,对于某种场合,可以把邮件存储到eml文件是一个很好的操作。
存储eml文件的相关操作如下所示。
private void btncreatefile_click(object sender, eventargs e)
{
string attachfile = path.combine(application.startuppath, "attachment/hotel2.png");
list<string> attachments = new list<string>();
attachments.add(attachfile);
string subject = "测试邮件";
string body = "<html>这是一份测试邮件,来自<font color=red><b>lumisoft.net</b></font></html>";
string bodyembedy = "<html>这是一份测试邮件<img src=\"cid:test.jpg\">,来自<font color=red><b>lumisoft.net</b></font></html>";
dictionary<string, string> embedlist = new dictionary<string, string>();
embedlist.add("test.jpg", "c:\\test.jpg");
//存储为eml文件
string path = path.combine(application.startuppath, "eml");
directoryutil.assertdirexist(path);
string emlfile = string.format("{0}/{1}.eml", path, datetime.now.tofiletime());
mime m = create_html_attachment_image(to, from, from, subject, bodyembedy, attachments, embedlist);
m.tofile(emlfile);
messageutil.showtips("ok");
}
发送eml文件操作如下所示。
private void btnsendfile_click(object sender, eventargs e)
{
using (smtp_client client = new smtp_client())
{
int smtpport = smtpusessl ? wellknownports.smtp_ssl : wellknownports.smtp;
client.connect(smtpserver, smtpport, smtpusessl);
client.ehlohelo(smtpserver);
//var authhh = new auth_sasl_client_plain(username, password);
//client.auth(authhh);
client.authenticate(username, password);
//string text = client.greetingtext;
client.mailfrom(from, -1);
client.rcptto(to);
string path = path.combine(application.startuppath, "eml");
string emlfile = directory.getfiles(path)[0];
var msg = mail_message.parsefromfile(emlfile);
memorystream stream = new memorystream();
msg.tostream(stream, new mime_encoding_encodedword(mime_encodedwordencoding.q, encoding.utf8), encoding.utf8);
stream.position = 0;
client.sendmessage(stream);
client.disconnect();
}
messageutil.showtips("ok");
}