Relay.cs
上传用户:horngjaan
上传日期:2009-12-12
资源大小:2882k
文件大小:13k
源码类别:

Email服务器

开发平台:

C#

  1. using System;
  2. using System.IO;
  3. using System.Data;
  4. using System.Threading;
  5. using System.Collections;
  6. using LumiSoft.Net.SMTP.Client;
  7. using LumiSoft.Net.Mime;
  8. namespace LumiSoft.MailServer
  9. {
  10. /// <summary>
  11. /// Mail relayer.
  12. /// </summary>
  13. public class Relay
  14. {
  15. private static bool      m_Delivering           = false;
  16. private static bool      m_DeliveringRetry      = false;
  17. private static int       m_MaxThreads           = 10;
  18. private static int       m_RelayInterval        = 10;
  19. private static int       m_RelayRetryInterval   = 30;
  20. private static int       m_RelayUndelWarning    = 1;
  21. private static int       m_RelayUndelivered     = 1;
  22. private static string    m_UndelWarningTemplate = "";
  23. private static string    m_UndeliveredTemplate  = "";
  24. private static string    m_SmartHost            = "";    // Smart host name eg. 'mail.neti.ee'.
  25. private static bool      m_UseSmartHost         = true;  // 
  26. private static string    m_Dns1                 = "";    // Primary dns server IP.
  27. private static string    m_Dns2                 = "";    // Secondary dns server IP.
  28. private static Hashtable m_RelayTable           = null;
  29. private MailServer m_pServer = null;
  30. /// <summary>
  31. /// Default constructor.
  32. /// </summary>
  33. /// <param name="server"></param>
  34. public Relay(MailServer server)
  35. {
  36. m_pServer = server;
  37. if(m_RelayTable == null){
  38. m_RelayTable = new Hashtable();
  39. }
  40. }
  41. #region function Deliver
  42. /// <summary>
  43. /// Sends relay mails.
  44. /// </summary>
  45. public void Deliver()
  46. {
  47. if(!m_Delivering){
  48. m_Delivering = true;
  49. RelayMails();
  50. m_Delivering = false;
  51. }
  52. }
  53. #endregion
  54. #region function DeliverRetry
  55. /// <summary>
  56. /// Sends retry(mails which couldn't be sent at immedeately) relay mails.
  57. /// </summary>
  58. public void DeliverRetry()
  59. {
  60. if(!m_DeliveringRetry){
  61. m_DeliveringRetry = true;
  62. SendRetryMails();
  63. m_DeliveringRetry = false;
  64. }
  65. }
  66. #endregion
  67. #region function RelayMails
  68. /// <summary>
  69. /// Relays all messages from relay directory.
  70. /// </summary>
  71. private void RelayMails()
  72. {
  73. try
  74. {
  75. string path = MailStore.MailStorePath + "Relay\";
  76. // Check if Directory exists, if not Create
  77. if(!Directory.Exists(path)){
  78. Directory.CreateDirectory(path);
  79. }
  80. string[] files = Directory.GetFiles(path,"*.eml");
  81. foreach(string file in files){
  82. // If maximum relay threads are exceeded,
  83. // wait when some gets available.
  84. while(m_RelayTable.Count > m_MaxThreads){
  85. Thread.Sleep(200);
  86. }
  87. Thread tr = new Thread(new ThreadStart(this.RelayMessage));
  88. AddThread(tr,file);
  89. tr.Start();
  90. }
  91. }
  92. catch(Exception x)
  93. {
  94. Error.DumpError(x,new System.Diagnostics.StackTrace());
  95. }
  96. }
  97. #endregion
  98. #region function RelayMessage
  99. private void RelayMessage()
  100. {
  101. try
  102. {
  103. if(!m_RelayTable.Contains(Thread.CurrentThread)){
  104. SCore.WriteLog(m_pServer.m_SartUpPath + "mailServiceError.log","RelayMails: params missing");
  105. return;
  106. }
  107. string messageFile = m_RelayTable[Thread.CurrentThread].ToString();
  108. bool sendOk = false;
  109. using(FileStream fs = File.Open(messageFile,FileMode.Open,FileAccess.ReadWrite)){
  110. // Get relay info
  111. RelayInfo relayInf = new RelayInfo(fs,1,1);
  112. string from = relayInf.From;
  113. if(from.Length == 0){
  114. from = relayInf.To;
  115. }
  116. SMTP_Client smtpClnt  = new SMTP_Client();
  117. smtpClnt.UseSmartHost = UseSmartHost;
  118. smtpClnt.SmartHost    = SmartHost;
  119. smtpClnt.DnsServers   = new string[]{Dns1,Dns2};
  120. sendOk = smtpClnt.Send(new string[]{relayInf.To},from,fs);
  121. }
  122. if(sendOk){
  123. // Message sended successfuly, may delete it
  124. File.Delete(messageFile);
  125. }
  126. // send failed
  127. else{
  128. // Move message to Retry folder
  129. string msgFileName = Path.GetFileName(messageFile);
  130. File.Move(messageFile,MailStore.MailStorePath + "Retry\" + msgFileName);
  131. }
  132. }
  133. catch(Exception x){
  134. if(!(x is IOException)){
  135. Error.DumpError(x,new System.Diagnostics.StackTrace());
  136. }
  137. }
  138. finally{
  139. RemoveThread(Thread.CurrentThread);
  140. }
  141. }
  142. #endregion
  143. #region function SendRetryMails
  144. /// <summary>
  145. /// Relay retry mails from retry directory.
  146. /// </summary>
  147. private void SendRetryMails()
  148. {
  149. try
  150. {
  151. string path = MailStore.MailStorePath + "Retry\";
  152. // Check if Directory exists, if not Create
  153. if(!Directory.Exists(path)){
  154. Directory.CreateDirectory(path);
  155. }
  156. string[] files = Directory.GetFiles(path,"*.eml");
  157. foreach(string file in files){
  158. // If maximum relay threads are exceeded,
  159. // wait when some gets available.
  160. while(m_RelayTable.Count > m_MaxThreads){
  161. Thread.Sleep(200);
  162. }
  163. Thread t = new Thread(new ThreadStart(this.SendRetryMail));
  164. AddThread(t,file);
  165. t.Start();
  166. }
  167. }
  168. catch(Exception x)
  169. {
  170. Error.DumpError(x,new System.Diagnostics.StackTrace());
  171. }
  172. }
  173. #endregion
  174. #region function SendRetryMail
  175. private void SendRetryMail()
  176. {
  177. try
  178. {
  179. if(!m_RelayTable.Contains(Thread.CurrentThread)){
  180. SCore.WriteLog(m_pServer.m_SartUpPath + "mailServiceError.log","SendRetryMail: params missing");
  181. return;
  182. }
  183. string messageFile = m_RelayTable[Thread.CurrentThread].ToString();
  184. using(FileStream fs = File.Open(messageFile,FileMode.Open,FileAccess.ReadWrite)){
  185. // Get relay info
  186. RelayInfo relayInf = new RelayInfo(fs,RelayUndelivered,RelayUndelWarning);
  187. string from = relayInf.From;
  188. if(from.Length == 0){
  189. from = relayInf.To;
  190. }
  191. SMTP_Client smtpClnt  = new SMTP_Client();
  192. smtpClnt.UseSmartHost = UseSmartHost;
  193. smtpClnt.SmartHost    = SmartHost;
  194. smtpClnt.DnsServers   = new string[]{Dns1,Dns2};
  195. if(smtpClnt.Send(new string[]{relayInf.To},from,fs)){
  196. fs.Close();
  197. // Message sended successfuly, may delete it
  198. File.Delete(messageFile);
  199. }
  200. // send failed
  201. else{
  202. string error = smtpClnt.Errors[0].ErrorText;
  203. // If destination recipient is invalid or Undelivered Date Exceeded, try to return message to sender
  204. if(smtpClnt.Errors[0].ErrorType == SMTP_ErrorType.InvalidEmailAddress || relayInf.IsUndeliveredDateExceeded){
  205. MakeUndeliveredNotify(relayInf,error,fs);
  206. fs.Close();
  207. // Undelivery note made, may delete message
  208. if(relayInf.From.Length > 0){
  209. File.Delete(messageFile);
  210. }
  211. // There isn't return address, can't send undelivery note
  212. else{
  213. // Check if Directory exists, if not Create
  214. if(!Directory.Exists(MailStore.MailStorePath + "Undelivered\")){
  215. Directory.CreateDirectory(MailStore.MailStorePath + "Undelivered\");
  216. }
  217. File.Move(messageFile,messageFile.Replace("Retry","Undelivered"));
  218. }
  219. }
  220. else if(relayInf.MustSendWarning){
  221. MakeUndeliveredWarning(relayInf,error,fs);
  222. byte[] mustSendWarningBit = System.Text.Encoding.ASCII.GetBytes("1");
  223. fs.Position = relayInf.WarningBitPos;
  224. fs.Write(mustSendWarningBit,0,mustSendWarningBit.Length);
  225. }
  226. }
  227. }
  228. }
  229. catch(Exception x){
  230. if(!(x is IOException)){
  231. Error.DumpError(x,new System.Diagnostics.StackTrace());
  232. }
  233. }
  234. finally{
  235. RemoveThread(Thread.CurrentThread);
  236. }
  237. }
  238. #endregion
  239. #region function MakeUndeliveredNotify
  240. /// <summary>
  241. /// Creates undelivered notify for user and places it to relay folder.
  242. /// </summary>
  243. /// <param name="relayInfo">Relay info</param>
  244. /// <param name="error">SMTP returned error text.</param>
  245. /// <param name="file">Messsage file.</param>
  246. private void MakeUndeliveredNotify(RelayInfo relayInfo,string error,Stream file)
  247. {
  248. try
  249. {
  250. // If sender isn't specified, we can't send undelivery notify to sender.
  251. // Just skip undelivery notify sending.
  252. if(relayInfo.From.Length == 0){
  253. return;
  254. }
  255. //LumiSoft.MailServer.Core.WriteLog("e:\mail.log","MakeUndeliveredNotify To:" + relayInfo.From + " " + DateTime.Now.ToString() + "msg date:" + relayInfo.MessageDate.ToString());
  256. // Make new message
  257. MimeMessage mime = new MimeMessage();
  258. mime.From    = "postmaster";
  259. mime.To      = new string[]{relayInfo.From};
  260. mime.Subject = "Undelivered mail warning";
  261. mime.Attachments.Add(new Attachment("data.eml",file));
  262. string bodyTxt = Relay.UndeliveredTemplate;
  263. bodyTxt = bodyTxt.Replace("<#RECEPTIENT>",relayInfo.To);
  264. bodyTxt = bodyTxt.Replace("<#ERROR>",error);
  265. mime.Body    = bodyTxt;
  266. byte[] data = System.Text.Encoding.Default.GetBytes(mime.Mime);
  267. MailStore.StoreMessage("",new MemoryStream(data),relayInfo.From,"",true);
  268. }
  269. catch(Exception x)
  270. {
  271. Error.DumpError(x,new System.Diagnostics.StackTrace());
  272. }
  273. }
  274. #endregion
  275. #region function MakeUndeliveredWarning
  276. /// <summary>
  277. /// Creates undelivered warning for user and places it to relay folder.
  278. /// </summary>
  279. /// <param name="relayInfo">Relay info</param>
  280. /// <param name="error">SMTP returned error text.</param>
  281. /// <param name="file">Messsage file.</param>
  282. private void MakeUndeliveredWarning(RelayInfo relayInfo,string error,Stream file)
  283. {
  284. try
  285. {
  286. // If sender isn't specified, we can't send warning to sender.
  287. // Just skip warning sending.
  288. if(relayInfo.From.Length == 0){
  289. return;
  290. }
  291. // Make new message
  292. MimeMessage mime = new MimeMessage();
  293. mime.From    = "postmaster";
  294. mime.To      = new string[]{relayInfo.From};
  295. mime.Subject = "Undelivered mail warning";
  296. mime.Attachments.Add(new Attachment("data.eml",file));
  297. string bodyTxt = Relay.UndelWarningTemplate;
  298.    bodyTxt = bodyTxt.Replace("<#RECEPTIENT>",relayInfo.To);
  299.    bodyTxt = bodyTxt.Replace("<#ERROR>",error);
  300.    bodyTxt = bodyTxt.Replace("<#UNDELIVERED_HOURS>",relayInfo.DeviveringForHours.ToString()); 
  301. mime.Body    = bodyTxt;
  302. byte[] data = System.Text.Encoding.Default.GetBytes(mime.Mime);
  303. MailStore.StoreMessage("",new MemoryStream(data),relayInfo.From,"",true);
  304. }
  305. catch(Exception x)
  306. {
  307. Error.DumpError(x,new System.Diagnostics.StackTrace());
  308. }
  309. }
  310. #endregion
  311. #region function AddThread
  312. private void AddThread(Thread tr,string data)
  313. {
  314. lock(m_RelayTable){
  315. m_RelayTable.Add(tr,data);
  316. }
  317. }
  318. #endregion
  319. #region function RemoveThread
  320. private void RemoveThread(Thread t)
  321. {
  322. lock(m_RelayTable){
  323. if(!m_RelayTable.ContainsKey(t)){
  324. SCore.WriteLog(m_pServer.m_SartUpPath + "mailServiceError.log","RemoveThread: doesn't contain");
  325. }
  326. m_RelayTable.Remove(t);
  327. }
  328. }
  329. #endregion
  330.         
  331. #region Properties Implementation
  332. /// <summary>
  333. /// Gets or sets maximum relay threads.
  334. /// </summary>
  335. public static int MaxRelayThreads
  336. {
  337. get{ return m_MaxThreads; }
  338. set{ m_MaxThreads = value; }
  339. }
  340. /// <summary>
  341. /// Gets or sets relay interval.
  342. /// </summary>
  343. public static int RelayInterval
  344. {
  345. get{ return m_RelayInterval; }
  346. set{ m_RelayInterval = value; }
  347. }
  348. /// <summary>
  349. /// Gets or sets relay retry(delayed relay) interval.
  350. /// </summary>
  351. public static int RelayRetryInterval
  352. {
  353. get{ return m_RelayRetryInterval; }
  354. set{ m_RelayRetryInterval = value; }
  355. }
  356. /// <summary>
  357. /// Gets or sets undelivered wanrning minutes.
  358. /// </summary>
  359. public static int RelayUndelWarning
  360. {
  361. get{ return m_RelayUndelWarning; }
  362. set{ m_RelayUndelWarning = value; }
  363. }
  364. /// <summary>
  365. /// Gets or sets undelivered wanrning reply template.
  366. /// </summary>
  367. public static string UndelWarningTemplate
  368. {
  369. get{ return m_UndelWarningTemplate; }
  370. set{ m_UndelWarningTemplate = value; }
  371. }
  372. /// <summary>
  373. /// Gets or sets undelivered hours.
  374. /// </summary>
  375. public static int RelayUndelivered
  376. {
  377. get{ return m_RelayUndelivered; }
  378. set{ m_RelayUndelivered = value; }
  379. }
  380. /// <summary>
  381. /// Gets or sets undelivered reply template.
  382. /// </summary>
  383. public static string UndeliveredTemplate
  384. {
  385. get{ return m_UndeliveredTemplate; }
  386. set{ m_UndeliveredTemplate = value; }
  387. }
  388. /// <summary>
  389. /// Gets or sets if to use smart host.
  390. /// </summary>
  391. public static bool UseSmartHost
  392. {
  393. get{ return m_UseSmartHost; }
  394. set{ m_UseSmartHost = value; }
  395. }
  396. /// <summary>
  397. /// Gets or sets smart host.
  398. /// </summary>
  399. public static string SmartHost
  400. {
  401. get{ return m_SmartHost; }
  402. set{ m_SmartHost = value; }
  403. }
  404. /// <summary>
  405. /// Gets or sets smart host.
  406. /// </summary>
  407. public static string Dns1
  408. {
  409. get{ return m_Dns1; }
  410. set{ m_Dns1 = value; }
  411. }
  412. /// <summary>
  413. /// Gets or sets smart host.
  414. /// </summary>
  415. public static string Dns2
  416. {
  417. get{ return m_Dns2; }
  418. set{ m_Dns2 = value; }
  419. }
  420. /// <summary>
  421. /// Gets if delivering messages.
  422. /// </summary>
  423. public static bool IsDelivering
  424. {
  425. get{ return m_Delivering; }
  426. }
  427. /// <summary>
  428. /// Gets if delivering retry messages.
  429. /// </summary>
  430. public static bool IsDeliveringRetry
  431. {
  432. get{ return m_DeliveringRetry; }
  433. }
  434. #endregion
  435. }
  436. }