1 namespace System.Net.Mail
7 using System.ComponentModel;
8 using System.Net.Configuration;
9 using System.Threading;
10 using System.Threading.Tasks;
11 using System.Security;
12 using System.Security.Permissions;
13 using System.Security.Authentication;
14 using System.Security.Cryptography.X509Certificates;
15 using System.Net.NetworkInformation;
16 using System.Runtime.Versioning;
18 using System.Globalization;
20 public delegate void SendCompletedEventHandler(object sender, AsyncCompletedEventArgs e);
22 public enum SmtpDeliveryMethod {
24 SpecifiedPickupDirectory,
26 PickupDirectoryFromIis
31 public enum SmtpDeliveryFormat {
32 SevenBit = 0, // Legacy
33 International = 1, // SMTPUTF8 - Email Address Internationalization (EAI)
36 public class SmtpClient : IDisposable {
43 string targetName = null;
44 SmtpDeliveryMethod deliveryMethod = SmtpDeliveryMethod.Network;
45 SmtpDeliveryFormat deliveryFormat = SmtpDeliveryFormat.SevenBit; // Non-EAI default
46 string pickupDirectoryLocation = null;
47 SmtpTransport transport;
48 MailMessage message; //required to prevent premature finalization
50 MailAddressCollection recipients;
51 SendOrPostCallback onSendCompletedDelegate;
53 static volatile MailSettingsSectionGroupInternal mailConfiguration;
54 ContextAwareResult operationCompletedResult = null;
55 AsyncOperation asyncOp = null;
56 static AsyncCallback _ContextSafeCompleteCallback = new AsyncCallback(ContextSafeCompleteCallback);
57 static int defaultPort = 25;
58 internal string clientDomain = null;
59 bool disposed = false;
60 // true if the host and port change between calls to send or GetServicePoint
61 bool servicePointChanged = false;
62 ServicePoint servicePoint = null;
63 // (async only) For when only some recipients fail. We still send the e-mail to the others.
64 SmtpFailedRecipientException failedRecipientException;
65 // ports above this limit are invalid
66 const int maxPortValue = 65535;
68 public event SendCompletedEventHandler SendCompleted;
71 if (Logging.On) Logging.Enter(Logging.Web, "SmtpClient", ".ctor", "");
75 if (Logging.On) Logging.Exit(Logging.Web, "SmtpClient", ".ctor", this);
79 public SmtpClient(string host) {
80 if (Logging.On) Logging.Enter(Logging.Web, "SmtpClient", ".ctor", "host=" + host);
85 if (Logging.On) Logging.Exit(Logging.Web, "SmtpClient", ".ctor", this);
89 //?? should port throw or just default on 0?
90 public SmtpClient(string host, int port) {
91 if (Logging.On) Logging.Enter(Logging.Web, "SmtpClient", ".ctor", "host=" + host + ", port=" + port);
94 throw new ArgumentOutOfRangeException("port");
101 if (Logging.On) Logging.Exit(Logging.Web, "SmtpClient", ".ctor", this);
106 if (port == defaultPort || port == 0) {
107 new SmtpPermission(SmtpAccess.Connect).Demand();
110 new SmtpPermission(SmtpAccess.ConnectToUnrestrictedPort).Demand();
113 transport = new SmtpTransport(this);
114 if (Logging.On) Logging.Associate(Logging.Web, this, transport);
115 onSendCompletedDelegate = new SendOrPostCallback(SendCompletedWaitCallback);
117 if (MailConfiguration.Smtp != null)
119 if (MailConfiguration.Smtp.Network != null)
121 if (host == null || host.Length == 0) {
122 host = MailConfiguration.Smtp.Network.Host;
125 port = MailConfiguration.Smtp.Network.Port;
128 transport.Credentials = MailConfiguration.Smtp.Network.Credential;
129 transport.EnableSsl = MailConfiguration.Smtp.Network.EnableSsl;
131 if (MailConfiguration.Smtp.Network.TargetName != null)
132 targetName = MailConfiguration.Smtp.Network.TargetName;
134 // If the config file contains a domain to be used for the
135 // domain element in the client's EHLO or HELO message,
138 // We do not validate whether the domain specified is valid.
139 // It is up to the administrators or user to use the right
140 // value for their scenario.
142 // Note: per section 4.1.4 of RFC2821, the domain element of
143 // the HELO/EHLO should be used for logging purposes. An
144 // SMTP server should not decide to route an email based on
146 clientDomain = MailConfiguration.Smtp.Network.ClientDomain;
149 deliveryFormat = MailConfiguration.Smtp.DeliveryFormat;
151 deliveryMethod = MailConfiguration.Smtp.DeliveryMethod;
152 if (MailConfiguration.Smtp.SpecifiedPickupDirectory != null)
153 pickupDirectoryLocation = MailConfiguration.Smtp.SpecifiedPickupDirectory.PickupDirectoryLocation;
156 if (host != null && host.Length != 0) {
164 if (this.targetName == null)
165 targetName = "SMTPSVC/" + host;
167 if (clientDomain == null) {
168 // We use the local host name as the default client domain
169 // for the client's EHLO or HELO message. This limits the
170 // information about the host that we share. Additionally, the
171 // FQDN is not available to us or useful to the server (internal
172 // machine connecting to public server).
174 // SMTP RFC's require ASCII only host names in the HELO/EHLO message.
175 string clientDomainRaw = IPGlobalProperties.InternalGetIPGlobalProperties().HostName;
176 IdnMapping mapping = new IdnMapping();
179 clientDomainRaw = mapping.GetAscii(clientDomainRaw);
181 catch (ArgumentException) { }
183 // For some inputs GetAscii may fail (bad Unicode, etc). If that happens
184 // we must strip out any non-ASCII characters.
185 // If we end up with no characters left, we use the string "LocalHost". This
186 // matches Outlook behavior.
187 StringBuilder sb = new StringBuilder();
189 for (int i = 0; i < clientDomainRaw.Length; i++) {
190 ch = clientDomainRaw[i];
191 if ((ushort)ch <= 0x7F)
195 clientDomain = sb.ToString();
197 clientDomain = "LocalHost";
209 throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend));
214 throw new ArgumentNullException("value");
217 if (value == String.Empty)
219 throw new ArgumentException(SR.GetString(SR.net_emptystringset), "value");
222 value = value.Trim();
227 servicePointChanged = true;
239 throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend));
243 throw new ArgumentOutOfRangeException("value");
246 if (value != defaultPort) {
247 new SmtpPermission(SmtpAccess.ConnectToUnrestrictedPort).Demand();
252 servicePointChanged = true;
258 public bool UseDefaultCredentials {
260 return (transport.Credentials is SystemNetworkCredential) ? true : false;
264 throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend));
267 transport.Credentials = value ? CredentialCache.DefaultNetworkCredentials : null;
272 public ICredentialsByHost Credentials {
274 return transport.Credentials;
278 throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend));
281 transport.Credentials = value;
289 return transport.Timeout;
293 throw new InvalidOperationException(SR.GetString(SR.SmtpInvalidOperationDuringSend));
298 throw new ArgumentOutOfRangeException("value");
301 transport.Timeout = value;
306 public ServicePoint ServicePoint {
309 if (servicePoint == null || servicePointChanged) {
310 servicePoint = ServicePointManager.FindServicePoint(host, port);
311 // servicePoint is now correct for current host and port
312 servicePointChanged = false;
318 public SmtpDeliveryMethod DeliveryMethod {
320 return deliveryMethod;
323 deliveryMethod = value;
327 // Should we use EAI formats?
328 public SmtpDeliveryFormat DeliveryFormat {
330 return deliveryFormat;
333 deliveryFormat = value;
337 public string PickupDirectoryLocation {
338 [ResourceExposure(ResourceScope.Machine)]
339 [ResourceConsumption(ResourceScope.Machine)]
341 return pickupDirectoryLocation;
343 [ResourceExposure(ResourceScope.Machine)]
344 [ResourceConsumption(ResourceScope.Machine)]
346 pickupDirectoryLocation = value;
351 /// <para>Set to true if we need SSL</para>
353 public bool EnableSsl {
355 return transport.EnableSsl;
358 transport.EnableSsl = value;
363 /// Certificates used by the client for establishing an SSL connection with the server.
365 public X509CertificateCollection ClientCertificates {
367 return transport.ClientCertificates;
371 public string TargetName {
372 set { this.targetName = value; }
373 get { return this.targetName; }
376 private bool ServerSupportsEai {
378 return transport.ServerSupportsEai;
382 private bool IsUnicodeSupported() {
383 if (DeliveryMethod == SmtpDeliveryMethod.Network) {
384 return (ServerSupportsEai && (DeliveryFormat == SmtpDeliveryFormat.International));
386 else { // Pickup directories
387 return (DeliveryFormat == SmtpDeliveryFormat.International);
391 [ResourceExposure(ResourceScope.Machine)]
392 [ResourceConsumption(ResourceScope.Machine)]
393 internal MailWriter GetFileMailWriter(string pickupDirectory)
395 if (Logging.On) Logging.PrintInfo(Logging.Web, "SmtpClient.Send() pickupDirectory=" + pickupDirectory);
396 if (!Path.IsPathRooted(pickupDirectory))
397 throw new SmtpException(SR.GetString(SR.SmtpNeedAbsolutePickupDirectory));
399 string pathAndFilename;
401 filename = Guid.NewGuid().ToString() + ".eml";
402 pathAndFilename = Path.Combine(pickupDirectory, filename);
403 if (!File.Exists(pathAndFilename))
407 FileStream fileStream = new FileStream(pathAndFilename, FileMode.CreateNew);
408 return new MailWriter(fileStream);
411 protected void OnSendCompleted(AsyncCompletedEventArgs e)
413 if (SendCompleted != null) {
414 SendCompleted(this, e);
418 void SendCompletedWaitCallback(object operationState) {
419 OnSendCompleted((AsyncCompletedEventArgs)operationState);
423 public void Send(string from, string recipients, string subject, string body) {
425 throw new ObjectDisposedException(this.GetType().FullName);
427 //validation happends in MailMessage constructor
428 MailMessage mailMessage = new MailMessage(from, recipients, subject, body);
433 [ResourceExposure(ResourceScope.None)]
434 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
435 public void Send(MailMessage message) {
436 if (Logging.On) Logging.Enter(Logging.Web, this, "Send", message);
438 throw new ObjectDisposedException(this.GetType().FullName);
441 if (Logging.On) Logging.PrintInfo(Logging.Web, this, "Send", "DeliveryMethod=" + DeliveryMethod.ToString());
442 if (Logging.On) Logging.Associate(Logging.Web, this, message);
443 SmtpFailedRecipientException recipientException = null;
446 throw new InvalidOperationException(SR.GetString(SR.net_inasync));
449 if (message == null) {
450 throw new ArgumentNullException("message");
453 if (DeliveryMethod == SmtpDeliveryMethod.Network)
456 MailAddressCollection recipients = new MailAddressCollection();
458 if (message.From == null) {
459 throw new InvalidOperationException(SR.GetString(SR.SmtpFromRequired));
462 if (message.To != null) {
463 foreach (MailAddress address in message.To) {
464 recipients.Add(address);
467 if (message.Bcc != null) {
468 foreach (MailAddress address in message.Bcc) {
469 recipients.Add(address);
472 if (message.CC != null) {
473 foreach (MailAddress address in message.CC) {
474 recipients.Add(address);
478 if (recipients.Count == 0) {
479 throw new InvalidOperationException(SR.GetString(SR.SmtpRecipientRequired));
482 transport.IdentityRequired = false; // everything completes on the same thread.
487 timer = new Timer(new TimerCallback(this.TimeOutCallback), null, Timeout, Timeout);
488 bool allowUnicode = false;
489 string pickupDirectory = PickupDirectoryLocation;
492 switch (DeliveryMethod) {
494 case SmtpDeliveryMethod.PickupDirectoryFromIis:
495 pickupDirectory = IisPickupDirectory.GetPickupDirectory();
496 goto case SmtpDeliveryMethod.SpecifiedPickupDirectory;
497 #endif // !FEATURE_PAL
498 case SmtpDeliveryMethod.SpecifiedPickupDirectory:
500 throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl));
501 allowUnicode = IsUnicodeSupported(); // Determend by the DeliveryFormat paramiter
502 ValidateUnicodeRequirement(message, recipients, allowUnicode);
503 writer = GetFileMailWriter(pickupDirectory);
506 case SmtpDeliveryMethod.Network:
509 // Detected durring GetConnection(), restrictable using the DeliveryFormat paramiter
510 allowUnicode = IsUnicodeSupported();
511 ValidateUnicodeRequirement(message, recipients, allowUnicode);
512 writer = transport.SendMail(message.Sender ?? message.From, recipients,
513 message.BuildDeliveryStatusNotificationString(), allowUnicode, out recipientException);
516 this.message = message;
517 message.Send(writer, DeliveryMethod != SmtpDeliveryMethod.Network, allowUnicode);
519 transport.ReleaseConnection();
521 //throw if we couldn't send to any of the recipients
522 if (DeliveryMethod == SmtpDeliveryMethod.Network && recipientException != null) {
523 throw recipientException;
526 catch (Exception e) {
528 if (Logging.On) Logging.Exception(Logging.Web, this, "Send", e);
531 if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) {
538 throw new SmtpException(SR.GetString(SR.net_timeout));
541 if (e is SecurityException ||
542 e is AuthenticationException ||
548 throw new SmtpException(SR.GetString(SR.SmtpSendMailFailure), e);
557 if (Logging.On) Logging.Exit(Logging.Web, this, "Send", null);
561 [HostProtection(ExternalThreading = true)]
562 public void SendAsync(string from, string recipients, string subject, string body, object userToken) {
564 throw new ObjectDisposedException(this.GetType().FullName);
566 SendAsync(new MailMessage(from, recipients, subject, body), userToken);
570 [HostProtection(ExternalThreading = true)]
571 [ResourceExposure(ResourceScope.None)]
572 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
573 public void SendAsync(MailMessage message, object userToken) {
575 throw new ObjectDisposedException(this.GetType().FullName);
577 if (Logging.On) Logging.Enter(Logging.Web, this, "SendAsync", "DeliveryMethod=" + DeliveryMethod.ToString());
578 GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync Transport#" + ValidationHelper.HashString(transport));
581 throw new InvalidOperationException(SR.GetString(SR.net_inasync));
584 if (message == null) {
585 throw new ArgumentNullException("message");
588 if (DeliveryMethod == SmtpDeliveryMethod.Network)
591 recipients = new MailAddressCollection();
593 if (message.From == null) {
594 throw new InvalidOperationException(SR.GetString(SR.SmtpFromRequired));
597 if (message.To != null) {
598 foreach (MailAddress address in message.To) {
599 recipients.Add(address);
602 if (message.Bcc != null) {
603 foreach (MailAddress address in message.Bcc) {
604 recipients.Add(address);
607 if (message.CC != null) {
608 foreach (MailAddress address in message.CC) {
609 recipients.Add(address);
613 if (recipients.Count == 0) {
614 throw new InvalidOperationException(SR.GetString(SR.SmtpRecipientRequired));
620 this.message = message;
621 string pickupDirectory = PickupDirectoryLocation;
624 CredentialCache cache;
625 // Skip token capturing if no credentials are used or they don't include a default one.
626 // Also do capture the token if ICredential is not of CredentialCache type so we don't know what the exact credential response will be.
627 transport.IdentityRequired = Credentials != null && (Credentials is SystemNetworkCredential || (cache = Credentials as CredentialCache) == null || cache.IsDefaultInCache);
628 #endif // !FEATURE_PAL
630 asyncOp = AsyncOperationManager.CreateOperation(userToken);
631 switch (DeliveryMethod) {
633 case SmtpDeliveryMethod.PickupDirectoryFromIis:
634 pickupDirectory = IisPickupDirectory.GetPickupDirectory();
635 goto case SmtpDeliveryMethod.SpecifiedPickupDirectory;
636 #endif // !FEATURE_PAL
637 case SmtpDeliveryMethod.SpecifiedPickupDirectory:
640 throw new SmtpException(SR.GetString(SR.SmtpPickupDirectoryDoesnotSupportSsl));
641 writer = GetFileMailWriter(pickupDirectory);
642 bool allowUnicode = IsUnicodeSupported();
643 ValidateUnicodeRequirement(message, recipients, allowUnicode);
644 message.Send(writer, true, allowUnicode);
649 transport.ReleaseConnection();
650 AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(null, false, asyncOp.UserSuppliedState);
652 asyncOp.PostOperationCompleted(onSendCompletedDelegate, eventArgs);
656 case SmtpDeliveryMethod.Network:
658 operationCompletedResult = new ContextAwareResult(transport.IdentityRequired, true, null, this, _ContextSafeCompleteCallback);
659 lock (operationCompletedResult.StartPostingAsyncOp())
661 GlobalLog.Print("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync calling BeginConnect. Transport#" + ValidationHelper.HashString(transport));
662 transport.BeginGetConnection(ServicePoint, operationCompletedResult, ConnectCallback, operationCompletedResult);
663 operationCompletedResult.FinishPostingAsyncOp();
669 catch (Exception e) {
672 if (Logging.On) Logging.Exception(Logging.Web, this, "Send", e);
674 if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) {
680 throw new SmtpException(SR.GetString(SR.net_timeout));
683 if (e is SecurityException ||
684 e is AuthenticationException ||
690 throw new SmtpException(SR.GetString(SR.SmtpSendMailFailure), e);
693 if (Logging.On) Logging.Exit(Logging.Web, this, "SendAsync", null);
694 GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsync");
699 public void SendAsyncCancel() {
701 throw new ObjectDisposedException(this.GetType().FullName);
703 if (Logging.On) Logging.Enter(Logging.Web, this, "SendAsyncCancel", null);
704 GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel");
706 if (!InCall || cancelled) {
713 if (Logging.On) Logging.Exit(Logging.Web, this, "SendAsyncCancel", null);
714 GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendAsyncCancel");
719 //************* Task-based async public methods *************************
720 [HostProtection(ExternalThreading = true)]
721 public Task SendMailAsync(string from, string recipients, string subject, string body)
723 var message = new MailMessage(from, recipients, subject, body);
724 return SendMailAsync(message);
727 [HostProtection(ExternalThreading = true)]
728 public Task SendMailAsync(MailMessage message)
730 // Create a TaskCompletionSource to represent the operation
731 var tcs = new TaskCompletionSource<object>();
733 // Register a handler that will transfer completion results to the TCS Task
734 SendCompletedEventHandler handler = null;
735 handler = (sender, e) => HandleCompletion(tcs, e, handler);
736 this.SendCompleted += handler;
738 // Start the async operation.
739 try { this.SendAsync(message, tcs); }
742 this.SendCompleted -= handler;
746 // Return the task to represent the asynchronous operation
750 private void HandleCompletion(TaskCompletionSource<object> tcs, AsyncCompletedEventArgs e, SendCompletedEventHandler handler)
752 if (e.UserState == tcs)
754 try { this.SendCompleted -= handler; }
757 if (e.Error != null) tcs.TrySetException(e.Error);
758 else if (e.Cancelled) tcs.TrySetCanceled();
759 else tcs.TrySetResult(null);
765 //*********************************
767 //********************************
768 internal bool InCall {
777 internal static MailSettingsSectionGroupInternal MailConfiguration {
779 if (mailConfiguration == null) {
780 mailConfiguration = MailSettingsSectionGroupInternal.GetSection();
782 return mailConfiguration;
787 void CheckHostAndPort() {
789 if (host == null || host.Length == 0) {
790 throw new InvalidOperationException(SR.GetString(SR.UnspecifiedHost));
792 if (port <= 0 || port > maxPortValue) {
793 throw new InvalidOperationException(SR.GetString(SR.InvalidPort));
798 void TimeOutCallback(object state) {
806 void Complete(Exception exception, IAsyncResult result) {
807 ContextAwareResult operationCompletedResult = (ContextAwareResult)result.AsyncState;
808 GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::Complete");
811 //any exceptions were probably caused by cancellation, clear it.
815 // An individual failed recipient exception is benign, only abort here if ALL the recipients failed.
816 else if (exception != null && (!(exception is SmtpFailedRecipientException) || ((SmtpFailedRecipientException)exception).fatal))
818 GlobalLog.Print("SmtpClient#" + ValidationHelper.HashString(this) + "::Complete Exception: " + exception.ToString());
821 if (!(exception is SmtpException)) {
822 exception = new SmtpException(SR.GetString(SR.SmtpSendMailFailure), exception);
826 if (writer != null) {
830 // Close may result in a DataStopCommand and the server may return error codes at this time.
831 catch (SmtpException se) {
835 transport.ReleaseConnection();
839 operationCompletedResult.InvokeCallback(exception);
841 GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::Complete");
844 static void ContextSafeCompleteCallback(IAsyncResult ar)
846 ContextAwareResult result = (ContextAwareResult)ar;
847 SmtpClient client = (SmtpClient)ar.AsyncState;
848 Exception exception = result.Result as Exception;
849 AsyncOperation asyncOp = client.asyncOp;
850 AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(exception, client.cancelled, asyncOp.UserSuppliedState);
851 client.InCall = false;
852 client.failedRecipientException = null; // Reset before the next send.
853 asyncOp.PostOperationCompleted(client.onSendCompletedDelegate, eventArgs);
856 void SendMessageCallback(IAsyncResult result) {
857 GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback");
859 message.EndSend(result);
860 // If some recipients failed but not others, throw AFTER sending the message.
861 Complete(failedRecipientException, result);
863 catch (Exception e) {
866 GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMessageCallback");
870 void SendMailCallback(IAsyncResult result) {
871 GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
873 writer = transport.EndSendMail(result);
874 // If some recipients failed but not others, send the e-mail anyways, but then return the
875 // "Non-fatal" exception reporting the failures. The sync code path does it this way.
876 // Fatal exceptions would have thrown above at transport.EndSendMail(...)
877 SendMailAsyncResult sendResult = (SendMailAsyncResult)result;
878 // Save these and throw them later in SendMessageCallback, after the message has sent.
879 failedRecipientException = sendResult.GetFailedRecipientException();
884 GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
889 Complete(null, result);
892 message.BeginSend(writer, DeliveryMethod != SmtpDeliveryMethod.Network,
893 ServerSupportsEai, new AsyncCallback(SendMessageCallback), result.AsyncState);
896 catch (Exception e) {
899 GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::SendMailCallback");
903 void ConnectCallback(IAsyncResult result) {
904 GlobalLog.Enter("SmtpClient#" + ValidationHelper.HashString(this) + "::ConnectCallback");
906 transport.EndGetConnection(result);
908 Complete(null, result);
911 // Detected durring Begin/EndGetConnection, restrictable using DeliveryFormat
912 bool allowUnicode = IsUnicodeSupported();
913 ValidateUnicodeRequirement(message, recipients, allowUnicode);
914 transport.BeginSendMail(message.Sender ?? message.From, recipients,
915 message.BuildDeliveryStatusNotificationString(), allowUnicode,
916 new AsyncCallback(SendMailCallback), result.AsyncState);
919 catch (Exception e) {
922 GlobalLog.Leave("SmtpClient#" + ValidationHelper.HashString(this) + "::ConnectCallback");
925 // After we've estabilished a connection and initilized ServerSupportsEai,
926 // check all the addresses for one that contains unicode in the username/localpart.
927 // The localpart is the only thing we cannot succesfully downgrade.
928 private void ValidateUnicodeRequirement(MailMessage message,
929 MailAddressCollection recipients, bool allowUnicode)
931 // Check all recipients, to, from, sender, bcc, cc, etc...
932 // GetSmtpAddress will throw if !allowUnicode and the username contains non-ascii
933 foreach (MailAddress address in recipients)
935 address.GetSmtpAddress(allowUnicode);
937 if (message.Sender != null)
939 message.Sender.GetSmtpAddress(allowUnicode);
941 message.From.GetSmtpAddress(allowUnicode);
945 void GetConnection() {
946 if (!transport.IsConnected) {
947 transport.GetConnection(ServicePoint);
960 public void Dispose() {
962 GC.SuppressFinalize(this);
965 protected virtual void Dispose(bool disposing) {
966 if (disposing && !disposed ) {
967 if (InCall && !cancelled) {
972 if ((transport != null) && (servicePoint != null)) {
973 transport.CloseIdleConnections(servicePoint);