Skip to content
This repository has been archived by the owner on Jan 23, 2023. It is now read-only.
/ corefx Public archive

Initial commit to System.Net.Mail. #12416

Merged
merged 8 commits into from
Oct 11, 2016
Merged

Initial commit to System.Net.Mail. #12416

merged 8 commits into from
Oct 11, 2016

Conversation

Priya91
Copy link
Contributor

@Priya91 Priya91 commented Oct 6, 2016

Changes from Desktop implementation:

  • SmtpConnection uses TcpClient instead of ServicePointManager.
  • SslStream instead of internal TlsStream.
  • Negotiate, NTLM, Digest authentication protocols not ported due to
    dependency on internal NTAuthentication type. Authentication currently happens uses plain text login, SSL connections need to be used.
  • TcpClient connections are not pooled.
  • Getting mail settings from web.config files is not supported, as netstandard2.0 doesn't expose the System.Net.Configuration apis.
  • Sending mail to IIS pickup directory currently throws NotSupportedException. Desktop uses COM types for this API, investigation on partially supporting this feature on Windows is pending.

Notes:

  • Tests will be added separately.
  • Please review SmtpConnection.cs and TlsStream.cs files for correctness, they have changed functionally from Desktop code.
  • The TcpClient connect does not have Connect(), BeginConnect() and EndConnect() in .NET Core contract yet, once that's available, the SendAsync should use the async connect methods. - Update: Added now

Did a test locally using the SmtpClient.Send() and SmtpClient.SendAsync() , was able to successfully send emails to google smpt server with tls authentication.

cc @stephentoub @ericeil @CIPop @davidsh @geoffkizer @tijoytom @karelz

@davidsh
Copy link
Contributor

davidsh commented Oct 6, 2016

I'm a little confused. I thought we were putting System.Net.Mail.* into the System.Net.Mail contract and not the Mime contract? And I also thought we were merging System.Net.Mime contract back into System.Net.Mail?

So, should we just assume, for now, that this entire contract implementation of System.Net.Mime (which now will include System.Net.Mail.* types) will be renamed to System.Net.Mail contract?

@stephentoub
Copy link
Member

So, should we just assume, for now, that this entire contract implementation of System.Net.Mime (which now will include System.Net.Mail.* types) will be renamed to System.Net.Mail contract?

Yes, the contract/assembly should be renamed to System.Net.Mail. @Priya91, can you do that as part of this change?

// Parse a comma separated list of MailAddress's
//
// Throws a FormatException if any MailAddress is invalid.
internal static IList<MailAddress> ParseMultipleAddresses(string data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I realize the desktop code returns IList<MailAddress>, but it would be more efficient for callers to enumerate the result if this was changed to List<MailAddress>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

@@ -283,7 +302,7 @@ private static string ParseDisplayName(string data, ref int index, bool expectMu

// Do not include the Comma (if any), and because there were no bounding quotes,
// trim extra whitespace.
displayName = data.SubstringTrim(index + 1, startingIndex - index);
displayName = data.Substring(index + 1, startingIndex - index).Trim();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was there a reason this changed? SubstringTrim will only allocate one string instead of two strings for the separate Substring and Trim operations.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

@@ -4,6 +4,7 @@

using System.Diagnostics;
using System.Net.Mime;
using System.Collections.Generic;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "Remove and Sort" usings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

protected DelegatedStream(Stream stream)
{
if (stream == null)
throw new ArgumentNullException("stream");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: nameof(stream)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

{
if (disposed)
{
throw new ObjectDisposedException(this.GetType().FullName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the this. isn't necessary and can be removed.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

{
if (_disposed)
{
throw new ObjectDisposedException(this.GetType().FullName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: the this. is unnecessary and can be removed. Applies throughout (I'll stop commenting on it).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.


if (item == null)
{
throw new ArgumentNullException("item");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: nameof(item). Applies throughout (I'll stop commenting on it).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

return;
}

foreach (AlternateView view in this)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not necessarily for this PR, but a follow-up improvement would be to explicitly pass a new List<AlternateView> to the base Collection<T> constructor from this type's constructor , and then cast Items to List<AlternateView> here to enumerate the collection more efficiently (avoiding the enumerator allocation and overhead).

internal static string ShortNameFromFile(string fileName)
{
string name;
int start = fileName.LastIndexOfAny(new char[] { '\\', ':' }, fileName.Length - 1, fileName.Length);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Cache the char[] in a readonly static field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

}
else
{
if (value.IndexOfAny(new char[] { '<', '>' }) != -1)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Cache the char[] in a static readonly field.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

{
get
{
return String.Format(CultureInfo.InvariantCulture, "{0}@{1}", _userName, _host);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: return _userName + "@" + _host;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any specific reason?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Concatenating 3 strings is more efficient than going through string.Format.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

private string GetAddress(bool allowUnicode)
{
return String.Format(CultureInfo.InvariantCulture, "{0}@{1}",
GetUser(allowUnicode), GetHost(allowUnicode));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: return GetUser(allowUnicode) + "@" + GetHost(allowUnicode);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

{
get
{
return String.Format(CultureInfo.InvariantCulture, "<{0}>", Address);
Copy link
Contributor

@justinvp justinvp Oct 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: return "<" + Address + ">";

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.


internal string GetSmtpAddress(bool allowUnicode)
{
return String.Format(CultureInfo.InvariantCulture, "<{0}>", GetAddress(allowUnicode));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: return "<" + GetAddress(allowUnicode) + ">";

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

/// <returns></returns>
public override string ToString()
{
if (String.IsNullOrEmpty(DisplayName))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: String -> string

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

{
if (String.IsNullOrEmpty(DisplayName))
{
return this.Address;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: this. isn't necessary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

}
else
{
return String.Format("\"{0}\" {1}", DisplayName, SmtpAddress);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: return "\"" + DisplayName + "\" " + SmtpAddress;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

{
return false;
}
return ToString().Equals(value.ToString(), StringComparison.InvariantCultureIgnoreCase);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OrdinalIgnoreCase?

Copy link
Contributor Author

@Priya91 Priya91 Oct 6, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The email address can be a UTF-8 string with non-ascii characters in the local part of the address, reference here. In which case, lasst and laßt gives true under invariantcultureignorecase and false under ordinalignorecase

cc @CIPop

return ToString().GetHashCode();
}

private static EncodedStreamFactory s_encoderFactory = new EncodedStreamFactory();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: readonly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

//be appended.
if (MimeBasePart.IsAscii(_displayName, false) || allowUnicode)
{
encodedAddress = string.Format(CultureInfo.InvariantCulture, "\"{0}\"", _displayName);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: `encodedAddress = """ + _displayName + """;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

Copy link
Member

@jstedfast jstedfast Oct 13, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be better to be smarter about quoting the _displayName string so as to avoid situations where the _displayName string contains a double quote character as well as properly escaping backslash characters.

See https://github.com/jstedfast/MimeKit/blob/master/MimeKit/Utils/MimeUtils.cs#L562 for how this should be done to comply with the specifications.

first = false;
}

return builder.ToString(); ;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: extra semicolon

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

{
for (int i = 0; i < Headers.Count; i++)
{
if (string.Compare(Headers.GetKey(i), headerName,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: string.Equals

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

for (int i = 0; i < Headers.Count; i++)
{
if (string.Compare(Headers.GetKey(i), headerName,
StringComparison.InvariantCultureIgnoreCase) == 0)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OrdinalIgnoreCase?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as before.

{
internal static class SmtpAuthenticationManager
{
private static ArrayList s_modules = new ArrayList();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List<ISmtpAuthenticationModule>

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

using System;
using System.IO;
using System.Collections.Specialized;
using System.Net.Mime;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: "Remove and Sort". Applies throughout (I'll stop commenting on it).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

resolved.

@Priya91 Priya91 changed the title Initial commit to System.Net.Mime. Initial commit to System.Net.Mail. Oct 10, 2016
@davidsh
Copy link
Contributor

davidsh commented Oct 10, 2016

@Priya91 Regarding the changes from Desktop implementation especially the un-implemented functionality (authentication) and missing tests, please open up separate issues to track this work (which might be done by others).

@davidsh
Copy link
Contributor

davidsh commented Oct 10, 2016

Test OuterLoop CentOS7.1 Debug Build and Test
Test OuterLoop OSX Debug Build and Test
Test OuterLoop Ubuntu14.04 Debug Build and Test
Test OuterLoop Windows_NT Debug Build and Test

@Priya91
Copy link
Contributor Author

Priya91 commented Oct 10, 2016

@Priya91 Regarding the changes from Desktop implementation especially the un-implemented functionality (authentication) and missing tests, please open up separate issues to track this work (which might be done by others).

Yes will do. I am currently working on tests, and will have another PR for it.

@@ -199,6 +199,24 @@ public static void AssertFormat(string messageFormat, params object[] data)
}
}

public static void AssertFormat(bool condition, string messageFormat, params object[] data)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method should be renamed to just Assert. It's ok and expected to have multiple overloads of a method where only the number/type of parameters vary. I.e. Console.WriteLine

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Went along with the naming of already existing methods in this file. The Assert methods on this file didn't have formatting syntax, and there was another method AssertFormat that took in params array to allow formatting, hence added overload to already existing AssertFormat, to include a condition.

namespace System.Net
{
[EventSource(Name = "Microsoft-System-Net-Mail", LocalizationResources = "FxResources.System.Net.Mail.SR")]
internal sealed class WebEventSource : EventSource
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the class named WebEventSource? Smtp isn't doing "web" things like HTTP. Wouldn't it be better to be called something like MailEventSource ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SmtpClient uses a TraceSource named as Web on Desktop, kept the same naming scheme from Desktop code here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename as "EmailEventSource". Also, please add a GUID and update the documentation at https://github.com/dotnet/corefx/blob/master/Documentation/debugging/windows-instructions.md

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding proper ETW tracing! 👍

{
base.Close();

if (_sslStream != null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: pls use braces around the content of the if as per CoreFx coding guidlines.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will address the nit in a separate PR, as triggering outerloop CI again for this change does not add value.

<None Include="project.json" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: missing newline at end of file.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will address the nit in a separate PR, as triggering outerloop CI again for this change does not add value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file doesn't exist, System.Net.Mail.csproj is the current.

Copy link
Contributor

@davidsh davidsh left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a few comments. Otherwise, LGTM.

@Priya91
Copy link
Contributor Author

Priya91 commented Oct 10, 2016

Thanks for the review @davidsh

@Priya91
Copy link
Contributor Author

Priya91 commented Oct 10, 2016

Centos run failed with

Discovering: System.Net.Requests.Tests
16:04:55   Discovered:  System.Net.Requests.Tests
16:04:55   Starting:    System.Net.Requests.Tests
16:04:59      System.Net.Tests.HttpWebRequestTest.GetResponseAsync_UseDefaultCredentials_ExpectSuccess(remoteServer: https://corefx-net.cloudapp.net/Echo.ashx) [FAIL]
16:04:59         System.Net.WebException : An error occurred while sending the request. Problem with the SSL CA cert (path? access rights?)
16:04:59         ---- System.Net.Http.HttpRequestException : An error occurred while sending the request.
16:04:59         -------- System.Net.Http.CurlException : Problem with the SSL CA cert (path? access rights?)

@Priya91
Copy link
Contributor Author

Priya91 commented Oct 10, 2016

@dotnet-bot test OuterLoop CentOS7.1 Debug

@Priya91
Copy link
Contributor Author

Priya91 commented Oct 10, 2016

filed issues #12526 #12529 #12535 #12536 #12537 #12538 on pending work items for .NET Core.

@Priya91
Copy link
Contributor Author

Priya91 commented Oct 11, 2016

Centos build failed with, not related to this change

/mnt/resource/j/workspace/dotnet_corefx/master/outerloop_centos7.1_debug_prtest/Tools/Microsoft.CSharp.Core.targets(67,5): error MSB6006: 
"/mnt/resource/j/workspace/dotnet_corefx/master/outerloop_centos7.1_debug_prtest/Tools/dotnetcli/dotnet" exited with code 139. [/mnt/resource/j/workspace/dotnet_corefx/master/outerloop_centos7.1_debug_prtest/src/System.Net.Primitives/tests/PerformanceTests/System.Net.Primitives.Performance.Tests.csproj]

@Priya91 Priya91 merged commit abc007c into dotnet:master Oct 11, 2016
@Priya91 Priya91 deleted the addinmime branch October 11, 2016 03:42
Copy link
Member

@CIPop CIPop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Priya91 PTAL


if (GlobalLog.IsEnabled && recipients.Count > 0)
{
GlobalLog.Assert("SmtpTransport::BeginSendMail()|recepients.Count <= 0");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/cc @stephentoub
Assert used to crash the process before. This is only logging silently.
Here any everywhere GlobalLog.Assert* is used, please follow the pattern used in other System.Net.* contracts and add Debug.Fail.

Copy link
Contributor Author

@Priya91 Priya91 Oct 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CIPop Can you file an issue on corefx with details, i don't follow.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Priya91 The code as written will not assert (crash the process when DEBUG is used).
#12674

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in #12749

namespace System.Net
{
[EventSource(Name = "Microsoft-System-Net-Mail", LocalizationResources = "FxResources.System.Net.Mail.SR")]
internal sealed class WebEventSource : EventSource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename as "EmailEventSource". Also, please add a GUID and update the documentation at https://github.com/dotnet/corefx/blob/master/Documentation/debugging/windows-instructions.md

namespace System.Net
{
[EventSource(Name = "Microsoft-System-Net-Mail", LocalizationResources = "FxResources.System.Net.Mail.SR")]
internal sealed class WebEventSource : EventSource
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for adding proper ETW tracing! 👍

@@ -9,6 +9,7 @@
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'netstandard1.7_Release|AnyCPU'" />
<ItemGroup>
<Compile Include="System.Net.Mime.cs" />
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is uncommon: we usually have a single .cs file. I actually prefer this but didn't know it's an option.
@ericstj, @weshaggard would it be safer to merge (do you foresee any tooling issues)?

@@ -79,10 +81,8 @@ internal void Append(string value, int offset, int count)
for (int i = 0; i < count; i++)
{
char c = value[offset + i];
if (c > 0xFF)
{
if ((ushort)c > 0xFF)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add the braces back.


namespace System.Net.Mail
{
[Serializable]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@karelz @weshaggard
/cc @davidsh

Are we adding [Serializable] back in netstandard? If yes, we need to track changes for other already-ported types.
Same question about CAS.

{
}

[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this isn't necessary anymore. If it is, please change the Justification text at System.dll.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it is

How do i verify that ?

Copy link
Member

@CIPop CIPop Oct 15, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The build should fail if removed. Either way, the Justification string is incorrect.

GetObjectData(serializationInfo, streamingContext);
}

[SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase", Justification = "System.dll is still using pre-v4 security model and needs this demand")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above.

InvokeCallback();
return false;
}
else if ((int)info.StatusCode != 334)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: add 334 to SmtpStatusCode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SmtpStatusCode is a public enum, adding to it is a new API change. Out of scope of this PR and netstandard2.0

try
{
LineInfo info = AuthCommand.EndSend(result);
if ((int)info.StatusCode == 235)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Add 235 to SmtpStatusCode.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SmtpStatusCode is a public enum, adding to it is a new API change. Out of scope of this PR and netstandard2.0

@wgutierrezr
Copy link

Hi
I was using MailKit because System.Net.Mail wasn't ready at that time. Is this ready for ASP.Net Core 2?
After upgraded my project to Core 2.0 MailKit is not working.

Regards

@karelz
Copy link
Member

karelz commented Sep 18, 2017

Please do not comment on long-closed issues or PRs. We are not monitoring them.
System.Net.Mail is in, but we consider it as compat API only. For serious mail work and latest protocols, etc. we recommend MailKit. I would recommend you find out why MailKit doesn't work. Upgrading .NET Core project 1.x to 2.0 should just work, aside from a handful of accidental breaking changes (which we are trying to fix in servicing).

picenka21 pushed a commit to picenka21/runtime that referenced this pull request Feb 18, 2022
Initial commit to System.Net.Mail.

Commit migrated from dotnet/corefx@abc007c
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants