-
-
Notifications
You must be signed in to change notification settings - Fork 372
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
To/From InternetAddresses are not being returned in case they only have a name #712
Comments
It's technically by design, but I can see how it could be argued either way. The reason I chose not to include incomplete email addresses is because a MailboxAddress insinuates that it has an address, but these cases do not. API's in MimeKit and MailKit that take a MailboxAddress argument all expect that the mailbox has a syntactically valid address (even if it's not valid because it doesn't exist or something). Maybe I can have an |
Thanks a lot for the swift update. I assumed that it was by design, but didn't know for sure. The IncompleteAddress would help if it possible. |
It would be a great enhancement to know if an email address is incomplete or invalid. Just the other day I encountered a customer who is sending emails where the From header contains an invalid email address. Exchange server actually displays it as is. Below is a mock example header (notice the dot):
In such cases the from property contains no email addresses whatsoever and I have to manually parse the from header, which is not ideal. |
@Olby2000 For that particular case, I believe you can use: var options = ParserOptions.Default.Clone ();
options.AddressParserCompliance = RfcCompliance.Loosest;
var message = MimeMessage.Load (options, fileName); Or at the very least, you can use those ParserOptions to parse the raw From header: var options = ParserOptions.Default.Clone ();
options.AddressParserCompliance = RfcCompliance.Loosest;
foreach (var header in message.Headers) {
if (header.Id == HeaderId.From) {
var from = InternetAddressList.Parse (options, header.RawValue);
}
} |
Just as an FYI, I have a similar case where the address is a phone number, not an e-mail address.
This format is used by Office 365 when you miss a call and the caller leaves a voicemail. You get an e-mail with the voicemail as an audio.mp3 and the phone number as the originator. |
@sliekens that is definitely an illegal syntax. |
I'm not surprised 😄 still thought it's worth mentioning |
FWIW, I looked into the IncompleteAddress idea a year or two ago and concluded it was going to be more difficult than I had hoped because it broke support for old-style UNIX mailbox addresses (e.g. diff --git a/MimeKit/InternetAddress.cs b/MimeKit/InternetAddress.cs
index 9326ebc7..145267d0 100644
--- a/MimeKit/InternetAddress.cs
+++ b/MimeKit/InternetAddress.cs
@@ -27,7 +27,6 @@
using System;
using System.Text;
using System.Globalization;
-using System.Collections.Generic;
using MimeKit.Utils;
diff --git a/MimeKit/InternetAddressList.cs b/MimeKit/InternetAddressList.cs
index 5b3c4ff4..6b71d3b7 100644
--- a/MimeKit/InternetAddressList.cs
+++ b/MimeKit/InternetAddressList.cs
@@ -589,10 +589,33 @@ namespace MimeKit {
if (isGroup && text[index] == (byte) ';')
break;
+ int startIndex = index;
+
if (!InternetAddress.TryParse (options, text, ref index, endIndex, groupDepth, flags, out var address)) {
+ Encoding encoding;
+ string name;
+
// skip this address...
while (index < endIndex && text[index] != (byte) ',' && (!isGroup || text[index] != (byte) ';'))
index++;
+
+ if (index > startIndex) {
+ name = Rfc2047.DecodePhrase (options, text, startIndex, index - startIndex, out int codepage);
+
+ if (codepage == -1)
+ codepage = 65001;
+
+ try {
+ encoding = Encoding.GetEncoding (codepage);
+ } catch {
+ encoding = Encoding.UTF8;
+ }
+ } else {
+ encoding = Encoding.UTF8;
+ name = string.Empty;
+ }
+
+ list.Add (new IncompleteAddress (encoding, MimeUtils.Unquote (name)));
} else {
list.Add (address);
}
diff --git a/MimeKit/MimeKit.csproj b/MimeKit/MimeKit.csproj
index 724579a2..aed9fe37 100644
--- a/MimeKit/MimeKit.csproj
+++ b/MimeKit/MimeKit.csproj
@@ -281,6 +281,7 @@
<Compile Include="HeaderListChangedEventArgs.cs" />
<Compile Include="HeaderListCollection.cs" />
<Compile Include="IMimeContent.cs" />
+ <Compile Include="IncompleteAddress.cs" />
<Compile Include="InternetAddress.cs" />
<Compile Include="InternetAddressList.cs" />
<Compile Include="MailboxAddress.cs" />
diff --git a/UnitTests/InternetAddressListTests.cs b/UnitTests/InternetAddressListTests.cs
index 906ac0ab..6db07d81 100644
--- a/UnitTests/InternetAddressListTests.cs
+++ b/UnitTests/InternetAddressListTests.cs
@@ -234,7 +234,14 @@ namespace UnitTests {
public void TestParseNameLessThan ()
{
AssertParseFails ("\"Name\" <");
- AssertTryParse ("\"Name\" <", "", new InternetAddressList ());
+ AssertTryParse ("\"Name\" <", "\"Name <\"", new InternetAddressList { new IncompleteAddress (Encoding.UTF8, "Name <") });
+ }
+
+ [Test]
+ public void TestParseIncompleteAddress ()
+ {
+ AssertParseFails ("John Craig Taylor");
+ AssertTryParse ("John Craig Taylor", "John Craig Taylor", new InternetAddressList { new IncompleteAddress (Encoding.UTF8, "John Craig Taylor") });
}
[Test] IncompleteAddress.cs: //
// IncompleteAddress.cs
//
// Author: Jeffrey Stedfast <[email protected]>
//
// Copyright (c) 2013-2022 .NET Foundation and Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
using System;
using System.Text;
using MimeKit.Utils;
namespace MimeKit {
/// <summary>
/// An incomplete address.
/// </summary>
/// <remarks>
/// An incomplete address.
/// </remarks>
public class IncompleteAddress : InternetAddress
{
internal IncompleteAddress (Encoding encoding, string displayName) : base (encoding, displayName)
{
}
/// <summary>
/// Clone the address.
/// </summary>
/// <remarks>
/// Clones the address.
/// </remarks>
/// <returns>The cloned address.</returns>
public override InternetAddress Clone ()
{
return new IncompleteAddress (Encoding, Name);
}
/// <summary>
/// Determines whether the specified <see cref="InternetAddress"/> is equal to the current <see cref="InternetAddress"/>.
/// </summary>
/// <remarks>
/// Compares two internet addresses to determine if they are identical or not.
/// </remarks>
/// <param name="other">The <see cref="InternetAddress"/> to compare with the current <see cref="InternetAddress"/>.</param>
/// <returns><c>true</c> if the specified <see cref="InternetAddress"/> is equal to the current
/// <see cref="InternetAddress"/>; otherwise, <c>false</c>.</returns>
public override bool Equals (InternetAddress other)
{
var incomplete = other as IncompleteAddress;
if (incomplete == null)
return false;
return Name == incomplete.Name;
}
/// <summary>
/// Returns a string representation of the <see cref="MailboxAddress"/>,
/// optionally encoding it for transport.
/// </summary>
/// <remarks>
/// Returns a string containing the formatted mailbox address. If the <paramref name="encode"/>
/// parameter is <c>true</c>, then the mailbox name will be encoded according to the rules defined
/// in rfc2047, otherwise the name will not be encoded at all and will therefor only be suitable
/// for display purposes.
/// </remarks>
/// <returns>A string representing the <see cref="MailboxAddress"/>.</returns>
/// <param name="options">The formatting options.</param>
/// <param name="encode">If set to <c>true</c>, the <see cref="MailboxAddress"/> will be encoded.</param>
/// <exception cref="System.ArgumentNullException">
/// <paramref name="options"/> is <c>null</c>.
/// </exception>
public override string ToString (FormatOptions options, bool encode)
{
if (options == null)
throw new ArgumentNullException (nameof (options));
if (encode) {
var builder = new StringBuilder ();
int lineLength = 0;
Encode (options, builder, true, ref lineLength);
return builder.ToString ();
}
if (!string.IsNullOrEmpty (Name))
return MimeUtils.Quote (Name);
return string.Empty;
}
internal override void Encode (FormatOptions options, StringBuilder builder, bool firstToken, ref int lineLength)
{
if (!string.IsNullOrEmpty (Name)) {
string name;
if (!options.International) {
var encoded = Rfc2047.EncodePhrase (options, Encoding, Name);
name = Encoding.ASCII.GetString (encoded, 0, encoded.Length);
} else {
name = Name;
}
if (lineLength + name.Length > options.MaxLineLength) {
if (name.Length > options.MaxLineLength) {
// we need to break up the name...
builder.AppendFolded (options, firstToken, name, ref lineLength);
} else {
// the name itself is short enough to fit on a single line,
// but only if we write it on a line by itself
if (!firstToken && lineLength > 1) {
builder.LineWrap (options);
lineLength = 1;
}
lineLength += name.Length;
builder.Append (name);
}
} else {
// we can safely fit the name on this line...
lineLength += name.Length;
builder.Append (name);
}
}
}
}
} |
I don't know if this is a bug or not, but I have an email (Problematic Email.zip) that in the To/From field it only has the Names and when parsing the mime, I don't get anything in the MimeMessage.To/From.
Describe the bug
A clear and concise description of what the bug is.
Platform (please complete the following information):
To Reproduce
Steps to reproduce the behavior:
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
Additional context
Add any other context about the problem here.
The text was updated successfully, but these errors were encountered: