1 using System; 2 using System.IO; 3 using System.Collections.Specialized; 4 using System.Net.Mime; 5 using System.Text; 6 7 namespace System.Net.Mail 8 { 9 /// <summary> 10 /// Summary description for MailMessage. 11 /// </summary> 12 13 14 15 16 17 //rfc3461 18 [Flags] 19 public enum DeliveryNotificationOptions { 20 None = 0, OnSuccess = 1, OnFailure = 2, Delay = 4, Never = (int)0x08000000 21 } 22 23 24 public class MailMessage:IDisposable 25 { 26 private AlternateViewCollection views; 27 AttachmentCollection attachments; 28 AlternateView bodyView = null; 29 string body = String.Empty; 30 Encoding bodyEncoding; 31 TransferEncoding bodyTransferEncoding = TransferEncoding.Unknown; 32 bool isBodyHtml = false; 33 bool disposed = false; 34 Message message; 35 DeliveryNotificationOptions deliveryStatusNotification = DeliveryNotificationOptions.None; 36 MailMessage()37 public MailMessage() { 38 message = new Message(); 39 if(Logging.On)Logging.Associate(Logging.Web, this, message); 40 string from = SmtpClient.MailConfiguration.Smtp.From; 41 42 if (from != null && from.Length > 0) { 43 message.From = new MailAddress(from); 44 } 45 } 46 MailMessage(string from, string to)47 public MailMessage(string from, string to) { 48 if (from == null) 49 throw new ArgumentNullException("from"); 50 51 if (to == null) 52 throw new ArgumentNullException("to"); 53 54 if (from == String.Empty) 55 throw new ArgumentException(SR.GetString(SR.net_emptystringcall,"from"), "from"); 56 57 if (to == String.Empty) 58 throw new ArgumentException(SR.GetString(SR.net_emptystringcall,"to"), "to"); 59 60 message = new Message(from,to); 61 if(Logging.On)Logging.Associate(Logging.Web, this, message); 62 } 63 64 MailMessage(string from, string to, string subject, string body)65 public MailMessage(string from, string to, string subject, string body):this(from,to) { 66 Subject = subject; 67 Body = body; 68 } 69 70 MailMessage(MailAddress from, MailAddress to)71 public MailMessage(MailAddress from, MailAddress to) { 72 if (from == null) 73 throw new ArgumentNullException("from"); 74 75 if (to == null) 76 throw new ArgumentNullException("to"); 77 78 message = new Message(from,to); 79 } 80 81 82 public MailAddress From { 83 get { 84 return message.From; 85 } 86 set { 87 if (value == null) { 88 throw new ArgumentNullException("value"); 89 } 90 message.From = value; 91 } 92 } 93 94 public MailAddress Sender { 95 get { 96 return message.Sender; 97 } 98 set { 99 message.Sender = value; 100 } 101 } 102 103 [Obsolete("ReplyTo is obsoleted for this type. Please use ReplyToList instead which can accept multiple addresses. http://go.microsoft.com/fwlink/?linkid=14202")] 104 public MailAddress ReplyTo { 105 get { 106 return message.ReplyTo; 107 } 108 set { 109 message.ReplyTo = value; 110 } 111 } 112 113 public MailAddressCollection ReplyToList { 114 get { 115 return message.ReplyToList; 116 } 117 } 118 119 public MailAddressCollection To { 120 get { 121 return message.To; 122 } 123 } 124 125 public MailAddressCollection Bcc { 126 get { 127 return message.Bcc; 128 } 129 } 130 131 public MailAddressCollection CC { 132 get { 133 return message.CC; 134 } 135 } 136 137 public MailPriority Priority{ 138 get { 139 return message.Priority; 140 } 141 set{ 142 message.Priority = value; 143 } 144 } 145 146 public DeliveryNotificationOptions DeliveryNotificationOptions { 147 get{ 148 return deliveryStatusNotification; 149 } 150 set{ 151 if (7 < (uint)value && value != DeliveryNotificationOptions.Never) { 152 throw new ArgumentOutOfRangeException("value"); 153 } 154 deliveryStatusNotification = value; 155 } 156 } 157 158 public string Subject { 159 get { 160 return (message.Subject != null ? message.Subject : String.Empty); 161 } 162 set { 163 message.Subject = value; 164 } 165 } 166 167 public Encoding SubjectEncoding { 168 get { 169 return message.SubjectEncoding; 170 } 171 set { 172 message.SubjectEncoding = value; 173 } 174 } 175 176 public NameValueCollection Headers { 177 get { 178 return message.Headers; 179 } 180 } 181 182 public Encoding HeadersEncoding { 183 get { 184 return message.HeadersEncoding; 185 } 186 set { 187 message.HeadersEncoding = value; 188 } 189 } 190 191 public string Body { 192 get { 193 return (body != null ? body : String.Empty); 194 } 195 196 set{ 197 body = value; 198 199 if (bodyEncoding == null && body != null) { 200 if (MimeBasePart.IsAscii(body,true)) { 201 bodyEncoding = Text.Encoding.ASCII; 202 } 203 else { 204 bodyEncoding = Text.Encoding.GetEncoding(MimeBasePart.defaultCharSet); 205 } 206 } 207 } 208 } 209 210 public Encoding BodyEncoding { 211 get { 212 return bodyEncoding; 213 } 214 set { 215 bodyEncoding = value; 216 } 217 } 218 219 public TransferEncoding BodyTransferEncoding { 220 get { 221 return bodyTransferEncoding; 222 } 223 set { 224 bodyTransferEncoding = value; 225 } 226 } 227 228 229 public bool IsBodyHtml{ 230 get{ 231 return isBodyHtml; 232 } 233 set{ 234 isBodyHtml = value; 235 } 236 } 237 238 239 public AttachmentCollection Attachments { 240 get { 241 if (disposed) { 242 throw new ObjectDisposedException(this.GetType().FullName); 243 } 244 245 if (attachments == null) { 246 attachments = new AttachmentCollection(); 247 } 248 return attachments; 249 } 250 } 251 public AlternateViewCollection AlternateViews { 252 get { 253 if (disposed) { 254 throw new ObjectDisposedException(this.GetType().FullName); 255 } 256 257 if (views == null) { 258 views = new AlternateViewCollection(); 259 } 260 261 return views; 262 } 263 } 264 Dispose()265 public void Dispose() 266 { 267 Dispose(true); 268 } 269 Dispose(bool disposing)270 protected virtual void Dispose(bool disposing) 271 { 272 if (disposing && !disposed) 273 { 274 disposed = true; 275 276 if(views != null){ 277 views.Dispose(); 278 } 279 if(attachments != null){ 280 attachments.Dispose(); 281 } 282 if(bodyView != null){ 283 bodyView.Dispose(); 284 } 285 } 286 } 287 288 SetContent(bool allowUnicode)289 private void SetContent(bool allowUnicode) { 290 291 //the attachments may have changed, so we need to reset the message 292 if(bodyView != null){ 293 bodyView.Dispose(); 294 bodyView = null; 295 } 296 297 if (AlternateViews.Count == 0 && Attachments.Count == 0) { 298 if (!string.IsNullOrEmpty(body)) { 299 bodyView = AlternateView.CreateAlternateViewFromString(body, bodyEncoding, (isBodyHtml?MediaTypeNames.Text.Html:null)); 300 message.Content = bodyView.MimePart; 301 } 302 } 303 else if (AlternateViews.Count == 0 && Attachments.Count > 0){ 304 MimeMultiPart part = new MimeMultiPart(MimeMultiPartType.Mixed); 305 306 if (!string.IsNullOrEmpty(body)) { 307 bodyView = AlternateView.CreateAlternateViewFromString(body, bodyEncoding, (isBodyHtml?MediaTypeNames.Text.Html:null)); 308 } 309 else{ 310 bodyView = AlternateView.CreateAlternateViewFromString(string.Empty); 311 } 312 313 part.Parts.Add(bodyView.MimePart); 314 315 foreach (Attachment attachment in Attachments) { 316 if(attachment != null){ 317 //ensure we can read from the stream. 318 attachment.PrepareForSending(allowUnicode); 319 part.Parts.Add(attachment.MimePart); 320 } 321 } 322 message.Content = part; 323 } 324 else{ 325 // 326 // DTS issue 610361 - we should not unnecessarily use Multipart/Mixed 327 // When there is no attachement and all the alternative views are of "Alternative" types. 328 // 329 MimeMultiPart part = null; 330 MimeMultiPart viewsPart = new MimeMultiPart(MimeMultiPartType.Alternative); 331 332 if (!string.IsNullOrEmpty(body)) { 333 bodyView = AlternateView.CreateAlternateViewFromString(body, bodyEncoding, null); 334 viewsPart.Parts.Add(bodyView.MimePart); 335 } 336 337 foreach (AlternateView view in AlternateViews) 338 { 339 //ensure we can read from the stream. 340 if (view != null) { 341 view.PrepareForSending(allowUnicode); 342 if (view.LinkedResources.Count > 0) 343 { 344 MimeMultiPart wholeView = new MimeMultiPart(MimeMultiPartType.Related); 345 wholeView.ContentType.Parameters["type"] = view.ContentType.MediaType; 346 wholeView.ContentLocation = view.MimePart.ContentLocation; 347 wholeView.Parts.Add(view.MimePart); 348 349 foreach (LinkedResource resource in view.LinkedResources) 350 { 351 //ensure we can read from the stream. 352 resource.PrepareForSending(allowUnicode); 353 354 wholeView.Parts.Add(resource.MimePart); 355 } 356 viewsPart.Parts.Add(wholeView); 357 } 358 else 359 { 360 viewsPart.Parts.Add(view.MimePart); 361 } 362 } 363 } 364 365 if (Attachments.Count > 0) 366 { 367 part = new MimeMultiPart(MimeMultiPartType.Mixed); 368 part.Parts.Add(viewsPart); 369 370 MimeMultiPart attachmentsPart = new MimeMultiPart(MimeMultiPartType.Mixed); 371 foreach (Attachment attachment in Attachments) 372 { 373 if (attachment != null) 374 { 375 //ensure we can read from the stream. 376 attachment.PrepareForSending(allowUnicode); 377 attachmentsPart.Parts.Add(attachment.MimePart); 378 } 379 } 380 part.Parts.Add(attachmentsPart); 381 message.Content = part; 382 } // If there is no Attachement, AND only "1" Alternate View AND !!no body!! 383 // then in fact, this is NOT a multipart region. 384 else if (viewsPart.Parts.Count == 1 && string.IsNullOrEmpty(body)) 385 { 386 message.Content = viewsPart.Parts[0]; 387 } 388 else 389 { 390 message.Content = viewsPart; 391 } 392 } 393 394 if (bodyView != null && bodyTransferEncoding != TransferEncoding.Unknown) 395 { 396 bodyView.TransferEncoding = bodyTransferEncoding; 397 } 398 } 399 Send(BaseWriter writer, bool sendEnvelope, bool allowUnicode)400 internal void Send(BaseWriter writer, bool sendEnvelope, bool allowUnicode) { 401 SetContent(allowUnicode); 402 message.Send(writer, sendEnvelope, allowUnicode); 403 } 404 BeginSend(BaseWriter writer, bool sendEnvelope, bool allowUnicode, AsyncCallback callback, object state)405 internal IAsyncResult BeginSend(BaseWriter writer, bool sendEnvelope, bool allowUnicode, 406 AsyncCallback callback, object state) { 407 SetContent(allowUnicode); 408 return message.BeginSend(writer, sendEnvelope, allowUnicode, callback, state); 409 } 410 EndSend(IAsyncResult asyncResult)411 internal void EndSend(IAsyncResult asyncResult) { 412 message.EndSend(asyncResult); 413 } 414 BuildDeliveryStatusNotificationString()415 internal string BuildDeliveryStatusNotificationString(){ 416 if(deliveryStatusNotification != DeliveryNotificationOptions.None){ 417 StringBuilder s = new StringBuilder(" NOTIFY="); 418 419 bool oneSet = false; 420 421 //none 422 if(deliveryStatusNotification == DeliveryNotificationOptions.Never){ 423 s.Append("NEVER"); 424 return s.ToString(); 425 } 426 427 if((((int)deliveryStatusNotification) & (int)DeliveryNotificationOptions.OnSuccess) > 0){ 428 s.Append("SUCCESS"); 429 oneSet = true; 430 } 431 if((((int)deliveryStatusNotification) & (int)DeliveryNotificationOptions.OnFailure) > 0){ 432 if(oneSet){ 433 s.Append(","); 434 } 435 s.Append("FAILURE"); 436 oneSet = true; 437 } 438 if((((int)deliveryStatusNotification) & (int)DeliveryNotificationOptions.Delay) > 0){ 439 if(oneSet){ 440 s.Append(","); 441 } 442 s.Append("DELAY"); 443 } 444 return s.ToString(); 445 } 446 return String.Empty; 447 } 448 } 449 } 450