Aspose.Email modifies X500 addresses in sender/recipient fields

In the case that there are X500 addresses used in the sender and recipient headers, Aspose will postprocess them (???):

  "Aspose" when {
    "i use X500 addresses" should {
      "pass them through to MIME verbatim" in {
        val mapiMessage = new MapiMessage()
        mapiMessage.setSenderEmailAddress("/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU")
        mapiMessage.setSenderName("David Stancu")

        val asMime = mapiMessage.toMailMessage(new MailConversionOptions())
        val baos = new ByteArrayOutputStream()
        asMime.save(baos)

        val bais = new ByteArrayInputStream(baos.toByteArray)
        val javaMailMessage = new MimeMessage(mailSession, bais)
        assert(
          javaMailMessage.getSender.toString ===
          """"David Stancu" </O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU>"""
        )
      }

      "pass them through verbatim if we toggle the flag?????" in {
        val mapiMessage = new MapiMessage()
        mapiMessage.setSenderEmailAddress("/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU")
        mapiMessage.setSenderName("David Stancu")

        val mco = new MailConversionOptions()
        mco.setKeepOriginalEmailAddresses(true)
        val asMime = mapiMessage.toMailMessage(mco)
        val baos = new ByteArrayOutputStream()
        asMime.save(baos)

        val bais = new ByteArrayInputStream(baos.toByteArray)
        val javaMailMessage = new MimeMessage(mailSession, bais)
        assert(
          javaMailMessage.getSender.toString ===
            """"David Stancu" </O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU>"""
        )
      }

      "maybe if i set it as a header?" in {
        val mapiMessage = new MapiMessage()
        mapiMessage.getHeaders.set("from", "/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU")

        val mco = new MailConversionOptions()
        mco.setKeepOriginalEmailAddresses(true)

        val asMime = mapiMessage.toMailMessage(new MailConversionOptions())
        val baos = new ByteArrayOutputStream()
        asMime.save(baos)

        val bais = new ByteArrayInputStream(baos.toByteArray)
        val javaMailMessage = new MimeMessage(mailSession, bais)

        // <> chars are from javax.mail presentation
        assert(
          javaMailMessage.getFrom.head.toString ===
            "</O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU>"
        )
      }
    }

In order

Test 1 and 2:

Expected :"["David Stancu" </O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU]>"
Actual   :"[<"David Stancu"]>"

Test 3:

Aspose is inserting a newline in the middle of the header??? (nvm, folding is OK, but why change the value)

Here is the output MIME:

From: "/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP
 /CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU"
Content-Type: text/plain
MIME-Version: 1.0
Expected :"<[/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU]>"
Actual   :"<["/O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP /CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU"]>"

setKeepOriginalEmailAddresses in MailConversionOptions appears to resolve SMTP addressess from PST metadata however it breaks the To fields in the process. I don’t know why this is the case and I will try to get you test data.


Given the severity of this bug (and the timestamp issue), we are expecting Aspose to step up and do the right thing: give us an extension on our license such that we can consume these updates once your team has fixed them. Without this goodwill gesture we will not plan on a renewal and will excise Aspose products from our stack entirely.

Our workaround:

      // "Fix" the From/To fields in the MapiMessage before serializing to MIME
      if (mo.getSenderSmtpAddress == null && mo.getSenderEmailAddress != null) {
        Try {
          mo.getHeaders.set("from", toIMCEA(mo.getSenderEmailAddress))
          mo.setSenderEmailAddress(null)
          mo.setSenderName(null)
        }
      }

      val recipients = TryNull(
        mo.getRecipients.asScala.groupBy(_.getRecipientType).mapValues(_.map(presentMapiRecipient))
      )

      recipients.foreach { rs =>
        val moHeaders = mo.getHeaders

        if (moHeaders.get("to") == null) {
          rs.get(MapiRecipientType.MAPI_TO).foreach(as => moHeaders.set("to", as.mkString(",")))
        }
        if (moHeaders.get("cc") == null) {
          rs.get(MapiRecipientType.MAPI_CC).foreach(as => moHeaders.set("cc", as.mkString(",")))
        }
        if (moHeaders.get("bcc") == null) {
          rs.get(MapiRecipientType.MAPI_BCC).foreach(as => moHeaders.set("bcc", as.mkString(",")))
        }
      }

Hello @dstancu,

Address formats, in headers like “From”, are generally governed by SMTP as described in RFC 5321, and the Internet Message Format as outlined in RFC 5322. The format used is SMTP, like user@example.com. Aspose.Email does not recognize such an address as an SMTP address, so the x500 formatted string is ignored.
Try using angle brackets to set the address to x500:

mapiMessage.getHeaders.set("from", "</O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU>")

or

mapiMessage.getHeaders.set("from", """"David Stancu" </O=EXCHANGELABS/OU=EXCHANGE ADMINISTRATIVE GROUP (FYDIBOHF23SPDLT)/CN=RECIPIENTS/CN=BLABLABLA-DAVID STANCU>""")

We know they aren’t valid SMTP addresses (which is why we are IMCEA encoding them). Adding brackets does not make it an SMTP address either. Some mail has raw X500 in it headers…we know they’re invalid MIME…but for example Java Mail will throw an exception to let us know.

This issue aside, toggling setKeepOriginalEmailAddresses(true) appears to break the To field in MIME output for messages that only have an X500 from address but otherwise have an SMTP to address. Can you look into this?

Hello @dstancu ,

We have opened a new ticket in our internal issue tracking system with the following ID: EMAILJAVA-35277.

Hello @dstancu,

Aspose.Email API supports two approaches for address resolution during Message Conversion:

1.Using MAPI Properties

The Aspose.Email API provides the ability to extract email addresses from corresponding MAPI properties within the message structure.

KeepOriginalEmailAddresses = false (default option)

In this case, MailMessage.From.Address is assigned from the MAPI property PR_SENT_REPRESENTING_EMAIL.
If the address format is x500, the MailMessage.From.Address will be empty, and the original x500 value will be set in the MailMessage.From.OriginalAddressString property.
MailMessage.From.DisplayName is assigned from the MAPI property PR_SENT_REPRESENTING_NAME.

MailMessage.Sender.Address is assigned from the MAPI property PR_SENDER_EMAIL_ADDRESS.
MailMessage.Sender.DisplayName is assigned from the MAPI property PR_SENDER_NAME.

MailMessage.To/CC/Bcc will be added from the MAPI Recipients properties.

2.Extracting from Mime Headers

Alternatively, the Aspose.Email API allows for retrieving email addresses directly from Mime headers stored within the PR_TRANSPORT_MESSAGE_HEADERS MAPI property.

KeepOriginalEmailAddresses = true

In this case, SMTP addresses will be assigned from the “From”, “Sent” Mime headers of the MAPI property PR_TRANSPORT_MESSAGE_HEADERS.
If the PR_TRANSPORT_MESSAGE_HEADERS property is missing, the fields are filled in as described in the first case.

MailMessage.To/CC/Bcc will be formed based on the “To”, “Cc”, “Bcc” Mime headers of the MAPI property PR_TRANSPORT_MESSAGE_HEADERS.