Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,20 @@ private static bool TryParseAddress(string data, bool expectMultipleAddresses, r
Debug.Assert(!string.IsNullOrEmpty(data));
Debug.Assert(index >= 0 && index < data.Length, $"Index out of range: {index}, {data.Length}");

// Check for CR or LF characters which are not allowed in mail addresses.
// Only scan on the first call (index == data.Length - 1) to avoid repeated O(n) scans
// when parsing multiple addresses from the same string.
if (index == data.Length - 1 && MailBnfHelper.HasCROrLF(data))
{
if (throwExceptionIfFail)
{
throw new FormatException(SR.MailAddressInvalidFormat);
}

parseAddressInfo = default;
return false;
}

// Parsed components to be assembled as a MailAddress later
string? displayName;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,13 +147,9 @@ public async Task TestMultipleMailDelivery()

[Theory]
[MemberData(nameof(SendMail_MultiLineDomainLiterals_Data))]
public async Task MultiLineDomainLiterals_Disabled_Throws(string from, string to)
public void MultiLineDomainLiterals_Disabled_Throws(string from, string to)
{
Smtp.Credentials = new NetworkCredential("Foo", "Bar");

using var msg = new MailMessage(@from, @to, "subject", "body");

await SendMail<SmtpException>(msg);
Assert.Throws<FormatException>(() => new MailMessage(@from, @to, "subject", "body"));
}

public static IEnumerable<object[]> SendMail_MultiLineDomainLiterals_Data()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -533,5 +533,39 @@ public void ParseAddresses_WithManyComplexAddresses_ShouldReadCorrectly()
Assert.Equal("\" asciin;,oqu o.tesws \"", result[5].User);
Assert.Equal("this.test.this", result[5].Host);
}

[Theory]
[InlineData("test\r@example.com")]
[InlineData("test\n@example.com")]
[InlineData("test\r\n@example.com")]
[InlineData("Display\r\nName <test@example.com>")]
[InlineData("test@example\r.com")]
[InlineData("test@example\n.com")]
[InlineData("test@example.com\r\n")]
public void TryParseAddress_WithCROrLF_ShouldThrow(string address)
{
Assert.Throws<FormatException>(() => MailAddressParser.TryParseAddress(address, out _, throwExceptionIfFail: true));
}

[Theory]
[InlineData("test\r@example.com")]
[InlineData("test\n@example.com")]
[InlineData("test\r\n@example.com")]
[InlineData("Display\r\nName <test@example.com>")]
[InlineData("test@example\r.com")]
[InlineData("test@example\n.com")]
[InlineData("test@example.com\r\n")]
public void TryParseAddress_WithCROrLF_ShouldReturnFalse(string address)
{
Assert.False(MailAddressParser.TryParseAddress(address, out _, throwExceptionIfFail: false));
}

[Fact]
public void ParseMultipleAddresses_WithCROrLF_ShouldThrow()
{
Assert.Throws<FormatException>(() => MailAddressParser.ParseMultipleAddresses("a@b.com, test\r\n@example.com"));
Assert.Throws<FormatException>(() => MailAddressParser.ParseMultipleAddresses("test\n@example.com, a@b.com"));
Assert.Throws<FormatException>(() => MailAddressParser.ParseMultipleAddresses("a@b.com, c@d.com, e\r@f.com"));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ public static IEnumerable<object[]> GetValidEmailTestData()
yield return new object[] { "testuser@[mail.com]" };
yield return new object[] { "testuser@[ mail.com] " };
yield return new object[] { "testuser@[mail.com ]" };
yield return new object[] { "testuser@[mail.com \r\n ]" };
yield return new object[] { "testuser@[ \r\n mail.com]" };
yield return new object[] { "testuser@[mail.com ]" };
yield return new object[] { "testuser@[ mail.com]" };
yield return new object[] { "testuser <testuser@mail.com>" };
yield return new object[] { "Test\u3044\u3069 User <testUser1@NCLMailTest.com>" };
Expand Down Expand Up @@ -88,8 +87,8 @@ public static IEnumerable<object[]> GetValidEmailTestData()
yield return new object[] { "\"disp \f lay\" <\"testsome\"@NCLMailTest.com>" };
yield return new object[] { "\"EscapedUnicode \\\u3044\\\u3069 display\" <testUser1@NCLMailTest.com>" };
yield return new object[] { "(Unicode \u3044 Comment) <\"testsome\"@NCLMailTest.com>" };
yield return new object[] { "\"display \r\n name\" <\"folding\"@domain.com>" };
yield return new object[] { "\"test\r\n test\"@mail.com" };
yield return new object[] { "\"display name\" <\"folding\"@domain.com>" };
yield return new object[] { "\"test test\"@mail.com" };
// Email Address Internationalization (EAI)
yield return new object[] { "UnicodeUserName \"Test\u3044\u3069\"@NCLMailTest.com" };
yield return new object[] { "<\"EscapedUnicode \\\u3044\\\u3069 User\"@NCLMailTest.com>" };
Expand Down Expand Up @@ -125,6 +124,10 @@ public static IEnumerable<object[]> GetInvalidEmailTestData()
yield return new object[] { "Bob \"display\" <user@host>" };
yield return new object[] { "testuser@[mail.com \r ]" };
yield return new object[] { "testuser@[mail.com \n ]" };
yield return new object[] { "testuser@[mail.com \r\n ]" };
yield return new object[] { "testuser@[ \r\n mail.com]" };
yield return new object[] { "\"display \r\n name\" <\"folding\"@domain.com>" };
yield return new object[] { "\"test\r\n test\"@mail.com" };
yield return new object[] { "testuser@[mail\u3069.com]" }; // No unicode allowed in square brackets
yield return new object[] { "invalid@unicode\uD800.com" }; // D800 is a high surrogate
yield return new object[] { "invalid@unicode\uD800.com" }; // D800 is a high surrogate
Expand Down
Loading