private void SendMailCallback(IAsyncResult result) { try { _writer = _transport.EndSendMail(result); // If some recipients failed but not others, send the e-mail anyway, but then return the // "Non-fatal" exception reporting the failures. The sync code path does it this way. // Fatal exceptions would have thrown above at transport.EndSendMail(...) SendMailAsyncResult sendResult = (SendMailAsyncResult)result; // Save these and throw them later in SendMessageCallback, after the message has sent. _failedRecipientException = sendResult.GetFailedRecipientException(); } catch (Exception e) { Complete(e, result); return; } try { if (_cancelled) { Complete(null, result); } else { _message !.BeginSend(_writer, DeliveryMethod != SmtpDeliveryMethod.Network, IsUnicodeSupported(), new AsyncCallback(SendMessageCallback), result.AsyncState !); } } catch (Exception e) { Complete(e, result); } }
public void SendAsync(MailMessage message, object?userToken) { ObjectDisposedException.ThrowIf(_disposed, this); try { if (InCall) { throw new InvalidOperationException(SR.net_inasync); } if (message == null) { throw new ArgumentNullException(nameof(message)); } if (DeliveryMethod == SmtpDeliveryMethod.Network) { CheckHostAndPort(); } _recipients = new MailAddressCollection(); if (message.From == null) { throw new InvalidOperationException(SR.SmtpFromRequired); } if (message.To != null) { foreach (MailAddress address in message.To) { _recipients.Add(address); } } if (message.Bcc != null) { foreach (MailAddress address in message.Bcc) { _recipients.Add(address); } } if (message.CC != null) { foreach (MailAddress address in message.CC) { _recipients.Add(address); } } if (_recipients.Count == 0) { throw new InvalidOperationException(SR.SmtpRecipientRequired); } InCall = true; _cancelled = false; _message = message; string?pickupDirectory = PickupDirectoryLocation; CredentialCache?cache; // Skip token capturing if no credentials are used or they don't include a default one. // Also do capture the token if ICredential is not of CredentialCache type so we don't know what the exact credential response will be. _transport.IdentityRequired = Credentials != null && (ReferenceEquals(Credentials, CredentialCache.DefaultNetworkCredentials) || (cache = Credentials as CredentialCache) == null || IsSystemNetworkCredentialInCache(cache)); _asyncOp = AsyncOperationManager.CreateOperation(userToken); switch (DeliveryMethod) { case SmtpDeliveryMethod.PickupDirectoryFromIis: throw new NotSupportedException(SR.SmtpGetIisPickupDirectoryNotSupported); case SmtpDeliveryMethod.SpecifiedPickupDirectory: { if (EnableSsl) { throw new SmtpException(SR.SmtpPickupDirectoryDoesnotSupportSsl); } _writer = GetFileMailWriter(pickupDirectory); bool allowUnicode = IsUnicodeSupported(); ValidateUnicodeRequirement(message, _recipients, allowUnicode); message.Send(_writer, true, allowUnicode); if (_writer != null) { _writer.Close(); } AsyncCompletedEventArgs eventArgs = new AsyncCompletedEventArgs(null, false, _asyncOp.UserSuppliedState); InCall = false; _asyncOp.PostOperationCompleted(_onSendCompletedDelegate, eventArgs); break; } case SmtpDeliveryMethod.Network: default: _operationCompletedResult = new ContextAwareResult(_transport.IdentityRequired, true, null, this, s_contextSafeCompleteCallback); lock (_operationCompletedResult.StartPostingAsyncOp()) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"Calling BeginConnect. Transport: {_transport}"); } _transport.BeginGetConnection(_operationCompletedResult, ConnectCallback, _operationCompletedResult, Host !, Port); _operationCompletedResult.FinishPostingAsyncOp(); } break; } } catch (Exception e) { InCall = false; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(this, e); } if (e is SmtpFailedRecipientException && !((SmtpFailedRecipientException)e).fatal) { throw; } Abort(); if (e is SecurityException || e is AuthenticationException || e is SmtpException) { throw; } throw new SmtpException(SR.SmtpSendMailFailure, e); } }