public void TestHeaders() { string custom1 = "customHeader"; string custom2 = "X-customeHeader2"; string headerValue = "custom value"; MailHeader testHeader = new MailHeader(custom1, headerValue); msg.AddCustomHeader(testHeader); Assertion.Assert(msg.CustomHeaders.Contains(testHeader)); msg.AddCustomHeader(custom2, headerValue); // Assertion.Assert(msg.CustomHeaders.Contains(testHeader)); }
public void TestSend() { try { Console.WriteLine("\r\n ----- Smtp Test Below -----"); msg.Subject = subject; msg.Body = body; msg.AddImage(@"..\lib\test attachments\test.jpg", "testimage"); msg.AddImage(@"..\lib\test attachments\test2.jpg", "testimage2"); msg.HtmlBody = "<body><table><tr><td><b>Here is an embedded IMAGE:<img src=\"cid:testimage\"></td></tr>\r\n<tr><td>Here's another: <img src=\"cid:testimage2\"></td></tr></table></body>"; msg.AddRecipient(ccAddress, AddressType.Cc); msg.AddRecipient(bccAddress, AddressType.Bcc); msg.AddAttachment(@"..\lib\test attachments\test.jpg"); msg.AddAttachment(new Attachment(new FileStream(@"..\lib\test attachments\test.htm", FileMode.Open, FileAccess.Read), "test.htm")); msg.AddCustomHeader("X-FakeTestHeader", "Fake Value"); msg.AddCustomHeader("X-AnotherFakeTestHeader", "Fake Value"); msg.Notification = true; msg.Charset = "ISO-8859-1"; msg.Priority = MailPriority.Low; smtp.Username = "******"; smtp.Password = "******"; for (int i = 0; i < 1; i++) { smtp.SendMail(msg); } } catch (SmtpException se) { Assertion.Fail("TestSend() threw a SmtpException: " + se.Message); } catch (System.Exception e) { Assertion.Fail("TestSend() threw a System.Exception: " + e.Message + "; Target: " + e.TargetSite); } }
protected void Init() { sender = "*****@*****.**"; recipient = "*****@*****.**"; cc = "*****@*****.**"; senderName = "FromName"; recipientName = "ToName"; ccName = "ccName"; subject = "Mail Message Test\r\n"; body = "Hello from MailMessageTest"; htmlBody = "<HTML><HEAD></HEAD><BODY bgColor=\"#00ffff\"><b>Hello Jane. This is the body of the HTML mail message.</b></BODY></HTML>"; charset = "us-ascii"; senderEmail = new EmailAddress(sender, senderName); recipientEmail = new EmailAddress(recipient, recipientName); ccEmail = new EmailAddress(cc, ccName); msg = new MailMessage(senderEmail, recipientEmail); msg.AddRecipient("*****@*****.**", AddressType.To); msg.AddRecipient("*****@*****.**", AddressType.To); msg.Subject = subject; msg.Body = body; msg.Charset = charset; msg.Priority = MailPriority.High; msg.HtmlBody = htmlBody.ToString(); msg.AddRecipient(ccEmail, AddressType.To); msg.AddRecipient(ccEmail, AddressType.Cc); msg.AddCustomHeader("X-Something", "Value"); msg.AddCustomHeader("X-SomethingElse", "Value"); msg.AddAttachment(@"..\lib\test attachments\test.jpg"); msg.AddAttachment(@"..\lib\test attachments\test.htm"); Attachment att = new Attachment(@"..\lib\test attachments\test.zip"); msg.AddAttachment(att); msg.Notification = true; }
public void MailTest() { using (SmtpClient smtpClient = new SmtpClient("smtp.163.com")) { smtpClient.Connected += (x, y) => _logger.Debug("mail", "Connected:{0}", y); smtpClient.Authenticated += (x, y) => _logger.Debug("mail", "Authenticated:{0}", y); smtpClient.StartedMessageTransfer += (x, y) => _logger.Debug("mail", "StartedMessageTransfer:{0}", y); smtpClient.EndedMessageTransfer += (x, y) => _logger.Debug("mail", "EndedMessageTransfer:{0}", y); smtpClient.Disconnected += (x, y) => _logger.Debug("mail", "Disconnected:{0}", y); smtpClient.Connect(); smtpClient.UserName = "******"; smtpClient.Password = "******"; smtpClient.Authenticate("*****@*****.**", "*****@*****.**"); MailAddress from = new MailAddress("Lsong", "*****@*****.**"); MailAddress to = new MailAddress("*****@*****.**"); MailAddress cc = new MailAddress("Test<*****@*****.**>"); MailMessage mailMessage = new MailMessage(from, to); mailMessage.AddRecipient(cc, AddressType.Cc); mailMessage.AddRecipient("*****@*****.**", AddressType.Bcc); mailMessage.Charset = "UTF-8"; mailMessage.Priority = MailPriority.High; mailMessage.Notification = true; mailMessage.AddCustomHeader("X-CustomHeader", "Value"); mailMessage.AddCustomHeader("X-CompanyName", "Value"); //string testCid = mailMessage.AddImage("C:\\test.bmp"); //mailMessage.AddAttachment("C:\\test.zip"); mailMessage.Subject = "This's a test Mail."; mailMessage.Body = "hello everybody ."; mailMessage.HtmlBody = string.Format("<html><body>hello everybody .<br /><img src='cid:{0}' /></body></html>", ""); smtpClient.SendMail(mailMessage); } using (PopClient popClient = new PopClient("pop.163.com")) { popClient.UserName = ""; popClient.Password = ""; popClient.Connect("pop.163.com", 110, false); popClient.Authenticate("*****@*****.**", "*****@*****.**"); int messageCount = popClient.GetMessageCount(); for (int i = messageCount; i > 1; i--) { //try //{ MessageHeader messageHeader = popClient.GetMessageHeaders(i); MailAddress sender = messageHeader.Sender; MailAddress from = messageHeader.From; List <MailAddress> to = messageHeader.To; string subject = messageHeader.Subject; _logger.Debug("mail", subject); if (sender != null) { _logger.Info("mail", "Sender:{0}", sender); } if (from != null) { _logger.Info("mail", "From:{0}", from); } if (to != null) { foreach (MailAddress mailAddress in to) { _logger.Info("mail", "TO:{0}", mailAddress); } } Message message = popClient.GetMessage(i); MessagePart textBody = message.FindFirstPlainTextVersion(); MessagePart htmlBody = message.FindFirstHtmlVersion(); if (textBody != null) { string text = textBody.GetBodyAsText(); System.Console.WriteLine(text); } else if (htmlBody != null) { string html = htmlBody.GetBodyAsText(); System.Console.WriteLine(html); } System.Console.ReadKey(); //} //catch (Exception exception) //{ // _logger.Error("mail", exception); //} } } }
private void DumpMapiProperties(IMessage inMsg, MailMessage outMsg) { String header, body; //Get the original transport headers, and parse them out String xportHdrs = MapiUtils.GetStringProperty(inMsg, Tags.PR_TRANSPORT_MESSAGE_HEADERS); if (xportHdrs == null) { return; } //Each header line consists of the header, whitespace, colon, whitespace, value Regex hdrLineRex = new Regex(@" (?# Match single- and multi-line SMTP headers ) (?<header> (?# The header element... ) [a-z0-9\-]+ (?# consists of letters, numbers, or hyphens.) ) (?# the header is followed by...) \s*:\s* (?# ...optional whitespace, a colon, additional optional whitespace...) (?<value> (?# ...and the value of the header, which is ...) .*? (?# ...any character, possibly spanning multiple lines...) ) (?=\r\n\S|\n\S|\z)(?# ...delimited by the start of another line w/ non-whitespace, or the end of the string) ", RegexOptions.IgnoreCase | //Obviously, case-insensitive RegexOptions.Multiline | //Need to match potentially multi-line SMTP headers RegexOptions.Singleline | //and . matches newlines as well RegexOptions.IgnorePatternWhitespace //Ignore the pattern whitespace included for readability ); foreach (Match match in hdrLineRex.Matches(xportHdrs)) { if (match.Success) { header = match.Groups["header"].Value; body = match.Groups["value"].Value; //If this header isn't one of the built-in ones that will be generated automatically //by OpenSmtp.net if (header.ToLower() != "to" && header.ToLower() != "from" && header.ToLower() != "reply-to" && header.ToLower() != "date" && header.ToLower() != "subject" && header.ToLower() != "cc" && header.ToLower() != "bcc" && header.ToLower() != "mime-version" && header.ToLower() != "content-type" && header.ToLower() != "content-transfer-encoding") { //OpenSmtp isn't smart enough to recognize multi-line header values, and wants to //quoted-printable them because of the CR/LF control chars. So, straighten multi-line values out body = Regex.Replace(body, @"\r\n\s+|\n\s+", " "); outMsg.AddCustomHeader(header, body); } } } //Now dump all of the MAPI properties as X- headers just in case they're needed Tags[] propIds; inMsg.GetPropList(0, out propIds); foreach (Tags propId in propIds) { //Skip properties that are too big or redundant if (propId == Tags.ptagBody || propId == Tags.ptagBodyHtml || propId == Tags.ptagHtml || propId == Tags.PR_BODY || propId == Tags.PR_BODY_HTML || propId == Tags.PR_RTF_COMPRESSED || propId == Tags.PR_TRANSPORT_MESSAGE_HEADERS) { continue; } header = String.Format("X-{0}", propId); try { Value val = MapiUtils.GetProperty(inMsg, propId); if (val is MapiBinary) { //Binary values aren't good for much continue; } if (val == null) { body = "<null>"; } else { body = val.ToString(); //Cannot have line breaks in SMTP headers, so if there are any, escape them body = body.Replace("\n", @"\n"); body = body.Replace("\r", @"\r"); body = body.Replace("\t", @"\t"); } outMsg.AddCustomHeader(header, body); } catch (MapiException e) { outMsg.AddCustomHeader("X-Exception", String.Format("Error getting property: {0}", e.Message)); } } }
public void AddMessage(IMessage msg) { //Check the msg class. If this is a non-delivery report, I don't know how to handle that String msgClass = MapiUtils.GetStringProperty(msg, Tags.PR_MESSAGE_CLASS); if (msgClass == "REPORT.IPM.Note.NDR") { return; } //A maildir is a folder full of files named thusly: // [timestamp].[uniqueid].[hostname] // // timestamp is simply the total seconds of the message time stamp // uniqueid is some system-generated ID that is unique within the namespace // of the hostname and timestamp. // hostname is the name of the host delivering the mail. // // since we're bulk-loading messages and can assume no other source is // submitting them, cop out on the uniqueid and just use a randomly-seeded, increasing counter // // In addition, for msgs in 'cur' (which all of these are), the file name can be followed by the following: // (source: http://cr.yp.to/proto/maildir.html) //When you move a file from new to cur, you have to change its name from uniq to uniq:info. Make sure to preserve the uniq string, so that separate messages can't bump into each other. // //info is morally equivalent to the Status field used by mbox readers. It'd be useful to have MUAs agree on the meaning of info, so I'm keeping a list of info semantics. Here it is. // //info starting with "1,": Experimental semantics. // //info starting with "2,": Each character after the comma is an independent flag. // // * Flag "P" (passed): the user has resent/forwarded/bounced this message to someone else. // * Flag "R" (replied): the user has replied to this message. // * Flag "S" (seen): the user has viewed this message, though perhaps he didn't read all the way through it. // * Flag "T" (trashed): the user has moved this message to the trash; the trash will be emptied by a later user action. // * Flag "D" (draft): the user considers this message a draft; toggled at user discretion. // * Flag "F" (flagged): user-defined flag; toggled at user discretion. // //New flags may be defined later. Flags must be stored in ASCII order: e.g., "2,FRS". // // From empirical study of Courier-IMAP Maildirs, there's also a 'S=whatever' before the flags. So: // whatever:2,S=12345,RS. // // Apparently this makes it faster for Courier to get messages sizes for quota enforcement purposes. However //tbird at least don't seem to know what to do w/ this, so I won't include size info. // //The contents of each file are in standard RFC 2822 format. //TODO: Use PR_MSG_STATUS for R, D, T, F DateTime recvTime = MapiUtils.GetSysTimeProperty(msg, Tags.ptagMsgDeliveryTime); int size = MapiUtils.GetLongProperty(msg, Tags.PR_MESSAGE_SIZE); int flags = MapiUtils.GetLongProperty(msg, Tags.PR_MESSAGE_FLAGS); bool read = ((flags & (int)MAPI33.WellKnownValues.PR_MESSAGE_FLAGS.Read) != 0); bool draft = ((flags & (int)MAPI33.WellKnownValues.PR_MESSAGE_FLAGS.Unsent) != 0); //Update the unique id _lastUniqueId += 1 + new Random().Next(100); String name = recvTime.Ticks.ToString(); name += "."; name += _lastUniqueId.ToString(); name += "."; name += System.Net.Dns.GetHostName(); //LAME: Colons in filenames aren't supported coz the path canonicalizer is too lazy to know the difference //between an alt data stream and just a plain colon. Bogus. name += ";2,"; //name += "S=" + size.ToString() + ","; tbird doesn't know what to do w/ this if (read) { name += "S"; } if (draft) { name += "D"; } //Create a message object MailMessage outMsg = new MailMessage(); outMsg.Date = recvTime; //Depending upon the message class, use different logic to populate the message if (msgClass == "IPM.Note") { ProcessMailMessage(msg, outMsg); } else if (msgClass == "IPM.Contact") { ProcessContact(msg, outMsg); return; //TODO: don't skip } else if (msgClass == "IPM.Calendar") { ProcessAppointment(msg, outMsg); return; //TODO: don't skip } else if (msgClass == "IPM.Task") { ProcessTask(msg, outMsg); return; //TODO: don't skip } else if (msgClass == "IPM.StickyNote") { ProcessNote(msg, outMsg); return; //TODO: don't skip } else { ProcessUnknownMsgClass(msg, outMsg); return; //TODO: don't skip } outMsg.AddCustomHeader("X-ConvertedFromMapi", String.Format("Adam Nelson's Mapi to Maildir Converter. {0}", DateTime.Now.ToString())); //Create the file in a temp location String tmpMsgFileName = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetTempFileName()); outMsg.Save(tmpMsgFileName); //Read the msg from the temp file, and write it to the destination file, //replacing the Windows line endings (CR LF) with UNIX (LF) String msgFileName = System.IO.Path.Combine(_curPath, name); const String LF = "\xa"; using (StreamReader sr = new StreamReader(tmpMsgFileName)) { using (StreamWriter sw = new StreamWriter(msgFileName)) { String line = null; while ( (line = sr.ReadLine()) != null) { sw.Write(line); sw.Write(LF); } } } File.Delete(tmpMsgFileName); //if there was a non-bogus receive time, set the date/time stamp //on the file to that time. if (recvTime != DateTime.MinValue) { //Set the date/time on the file to be the receive time //There seems to be an undocumented bug in the behavior of File.Set*Time. //Specifically, if it is used to set a time on a date with a different GMT //offset than the current date (eg, set the file to '3/1/04 12:00PM' (which is during //standard time in the Eastern time zone, and thus GMT-5) on '7/1/04' (which is //during daylight savings time in the Eastern time zone, and thus GMT-4), then //the resulting value displayed by Windows Explorer is one hour ahead. To continue //the example above, explorer would display the time for the file as //'1:00 PM' instead of '12:00 PM'. It's as though the timezone translation //is being performed when it should not. // //There is newsgroup chatter suggesting this has been seen before, but not confirmed //by MS. The Get*Time methods must reverse whatever transformation is applied //by the Set*Time methods, as they return the same time passed in. // //At any rate, the workaround is to apply a compensating reverse adjustment //That is, subtract from recvTime the difference in GMT offset on recvTime's date, //and on the current date //For EST, this will be -300 minutes (-5 hours) //For EDT, -240 minutes (-4 hours) double thenGmtOffset = (recvTime - recvTime.ToUniversalTime()).TotalMinutes; double nowGmtOffset = (DateTime.Now - DateTime.Now.ToUniversalTime()).TotalMinutes; //To continue the example above, this will be an offset of -60 minutes double compensatingOffset = thenGmtOffset - nowGmtOffset; //Can't possibly be 24 hours or more. System.Diagnostics.Debug.Assert(compensatingOffset < 24*60); DateTime fsTime = recvTime.AddMinutes(compensatingOffset); File.SetCreationTime(msgFileName, fsTime); File.SetLastWriteTime(msgFileName, fsTime); } }