Microsoft-graph-docs: How do I get mail Id after sending mail with this api

Created on 12 Jan 2019  ·  23Comments  ·  Source: microsoftgraph/microsoft-graph-docs

How do I get mail Id after sending mail with this api
https://graph.microsoft.com/v1.0/me/sendMail
its not sending any response, How do I know its mail Id


Document Details

Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

Most helpful comment

@kshitijrana that would be awesome, but emails are queued on Exchange and having this functionality will extend the response time (because mail must get send before You will get a response).
Currently, You only get confirmation that Exchange has registered Your request for processing (please correct me if I'm wrong). This is the async (the default) behavior as @sudostack described.

But for simple use cases, this would be the preferred way to go. The only thing missing is a parameter in the request that would inform Exchange to perform an synchronous operation and return all the information we normally query for.

But for large systems that need to send a lot of emails, the preferred way would be to use webhooks because the You use all the goodness of async operations - You send and forget and Exchange informs You that the email was sent.

All 23 comments

@bewithdhanu were You able to get mail id?

No I am not able to get message id after sending message.
As of document I just found it as it will responds with Status code: 202

Ref : https://docs.microsoft.com/en-us/previous-versions/office/office-365-api/api/version-2.0/mail-rest-operations#create-and-send-messages

This is by design. I'm assuming that you want to get the id of the message after it is saved in Sent Items?

If that's your need, the way to do it is to tag the message with a custom identifier, then find it in Sent Items after you've sent it.

Send the message with custom identifier

Send the message as you are now, but include a single-value extended property in the message payload.

What you should do is define your own GUID and property name, which then remains constant. You would then generate a unique value every time you send a message. For example, if you look at the sample payload below, I define the id of my singleValueExtendedProperty as String {630b1eb6-293a-4c92-ba78-a40aadad5ae7} Name SendMailId. The GUID is one I generated, and the name SendMailId is just something I defined. I would use this same id value every time I send mail, but I would change the value of the singleValueExtendedProperty to something unique.

Request

POST /me/sendmail
Content-type: application/json

{
  "message": {
    "subject": "Did you see last night's game?",
    "importance": "Low",
    "body": {
      "contentType": "HTML",
      "content": "They were <b>awesome</b>!"
    },
    "toRecipients": [
      {
        "emailAddress": {
          "address": "[email protected]"
        }
      }
    ],
    "singleValueExtendedProperties": [
      {
        "id": "String {630b1eb6-293a-4c92-ba78-a40aadad5ae7} Name SendMailId",
        "value": "1234"
      }
    ]
  }
}

Find the message by the custom identifier

Now you can find the message by using a $filter clause. You can also optionally include an $expand clause if you want the custom identifier to be included in the response.

Request

GET /me/messages?
$filter=singleValueExtendedProperties/Any(ep:ep/id eq 'String {630b1eb6-293a-4c92-ba78-a40aadad5ae7} Name SendMailId' and ep/value eq 'Food')&
$expand=singleValueExtendedProperties($filter=id eq 'String {630b1eb6-293a-4c92-ba78-a40aadad5ae7} Name SendMailId')

Response (truncated)

{
  "value": [
    {
      "id": "AAMkAGE1...",
      "subject": "Did you see last night's game?",
      "singleValueExtendedProperties": [
        {
          "id": "String {630b1eb6-293a-4c92-ba78-a40aadad5ae7} Name SendMailId",
          "value": "1234"
        }
      ]
    }
  ]
}

👍
Thax @jasonjoh

You can actually generate your own message id and send the mail with it.

POST https://graph.microsoft.com/v1.0/me/sendMail
Content-type: application/json

{
  "message": {
    "internetMessageId": "[valid rfc2822 message id]",
    ...
  }
}

@jasonjoh First of all, thanks for providing a useful example, but there's a point of confusion for me. Perhaps you can help clarify...

An extended property contains two fields, id and value

I have the same scenario as OP and I'm curious as to why a property's id field needs to include a GUID/namespace in the format of <datatype> {<GUID/namespace>} Name <some name>?

Why is a GUID/namespace needed in the property ID? It appears that the GUID is unique to a resource action as indicated by the name that you've chosen, SendMailId and it is static if I'm performing the same action over and over irrespective of who the user is.

I almost feel as though the id field is more of a key rather than an ID... aside from the one fact that querying for an extended property with a given id could return multiple records. Is that the idea? The id in an extended property is utilized for the purpose of grouping? If so, I don't understand why a GUID is needed so long as the key or id in your APIs' case is unique.

Would it be inadvisable to do the following?

{
  id: "String {MessageGUID} Name MessageGUID", // static "key"/id/namespace
  value: "d19ecf68-4960-45d6-96aa-dc6b34a03fbc" // unique resource identifier
}

// -- OR --

{
  id: "String {123} Name MessageGUID", static "key"/id/namespace
  value: "d19ecf68-4960-45d6-96aa-dc6b34a03fbc" // unique resource identifier
}

If I'm generating unique identifiers for each message, should I be generating another GUID/UUID for the value field, keeping the id field static?

I just don't understand why a property id needs a GUID as well as the property value (if I'm to provide a unique identifier for the message resource)

What's the recommendation for the name segment of the id string? Should it be unique per resource? Per resource action? Something else? From your docs here:

As a named property, identified by the extended property type, namespace, and a string name.

^ The above is a little too generic. As in, when do I know or what are the guidelines on when I need to provide a new GUID or a new name?

I'm currently writing an SDK for MS Graph, but am at a loss at how to codify this

Lastly, why isn't the open type extension recommended for this use case even though the docs seem to recommend them for Outlook resources, like message in our case? -- https://docs.microsoft.com/en-us/graph/api/resources/opentypeextension?view=graph-rest-1.0

The GUID in this case is what ensures uniqueness. The GUID serves as a namespace identifier. The idea is that your application defines a namespace, and any custom properties your application uses are in that namespace. So you only need to define a GUID once here. This is an older MAPI concept, and predates open extensions. You also really would only need to define one name here.

For open extensions, there are few problems. First, you can't filter on them, so that makes it a bit more work to find it in the Sent Items folder. I'm also not sure if open extensions are preserved when you send.

You can get the message ID from the Sent Items folder by this request https://graph.microsoft.com/v1.0/me/mailFolders/${sentMailboxId}/messages. It would be the first message in the array. However, make this request after a timeout function so that the mail is populated in Sent Items folder.

@kshitijrana while that may work for a single message send, I’m not sure this idea works for multiple message sends. I hesitate to rely on this if there’s no documentation stating that order is guaranteed. And if messages are sent on behalf of the user from different services asynchronously, this reconciliation becomes even more difficult. So this probably only works for a very simple and narrow use case. Am I right?

We have webhooks and they should be used to get id and other properties after the message was sent.
Right now You must pull (query) graph after x seconds until You find that email in Sent Items folder.
I've created a feature request that would allow us to get notifications when email was sent.
This would simplify everything so much.

  1. You send email using graph
  2. Email get send
  3. You get a webhook notification and You can read all the properties (for example sentDateTime).

If others need such functionality please upvote my feature request.

@sudostack You're right. If the account is being used from different services simultaneously, this will not guarantee the correct message ID.

@Misiu I like that idea. Yeah, that's precisely what I do at the moment in my organization's application code -- poll. I wrote an SDK that my application consumes. Our response to the 4xx status code that they supply when the message isn't yet available is to retry with delay. It isn't ideal or elegant, but a webhook notification would provide what is needed although the use-case is pretty limited to a few consuming clients like us. The alternative that I think Microsoft could supply is allowing the option of making a send synchronous and having the consuming client (us) pass an option for it, but it may not be possible or reasonable for Microsoft to have when considering service availability

@Misiu @sudostack Wouldn't it be better if send mail end point sends the relevant information with the response? Instead of the empty response that it sends right now. I think this might be better than having a web hook.

@kshitijrana that would be awesome, but emails are queued on Exchange and having this functionality will extend the response time (because mail must get send before You will get a response).
Currently, You only get confirmation that Exchange has registered Your request for processing (please correct me if I'm wrong). This is the async (the default) behavior as @sudostack described.

But for simple use cases, this would be the preferred way to go. The only thing missing is a parameter in the request that would inform Exchange to perform an synchronous operation and return all the information we normally query for.

But for large systems that need to send a lot of emails, the preferred way would be to use webhooks because the You use all the goodness of async operations - You send and forget and Exchange informs You that the email was sent.

@Misiu Thanks for explaining. I wasn't aware of the Exchange and how it works. What you say makes sense. Are there any resources you can tell me to gain more knowledge about this?

@kshitijrana I'm glad I could help :)
I've created this feature request for this type of notifications (webhooks). Please upvote it and spread the word. Maybe someday this will get implemented

@kshitijrana what @Misiu stated is what I meant, but to add, it isn't unique to Exchange.

In large scale distributed systems, "service availability" (the A in the CAP theorem) is what's typically deployed at scale (choosing P [partition tolerance] and A [availability]) over C [consistency].

They send you an ACK with a 202 (accepted status code) to let you know that they've received the request, but it isn't necessarily processed yet, so that your systems can keep humming along without waiting for a response. They likely process send/reply requests in serial in some queue, but if they had to ACK (acknowledge) AND process, then let you know that the work has been done, that's going to be a waiting game for us (the consuming client [they'd likely be trading availability]) and their resources could be locked up trying to do a synchronous operation (which blocks). An email system at scale needs to be highly concurrent -- therefore webhooks satisfies this need, as they can just dispatch a notification when the work is actually done (processed) instead of (acknowledgement and processing)

@sudostack @kshitijrana I'm currently building solution based on webhooks. I'm subscribing to sentitems folder.
I have a problem when trying to access SingleValueExtendedProperties but the basic concept works.
I'll share more info when everything will be working as expected 🙂

@sudostack Thanks for the information. I understand that the response for the API is just for the developer to know that the request has been registered and the system does the processing later. Doing it as a synchronous operation would involve more waiting time for the client's code (us) and makes their system less concurrent.
If you allow me to go a little off topic here, Gmail API gives the message ID as well as the thread ID (conversation ID in case of this API) in the response for the send mail API. So, would it be fair assume that they are performing a synchronous operation? I can only guess, but I think the request body of Gmail API's send mail endpoint which requires the entire email message to be RFC 2822 formatted and base 64 encoded requires less processing on their part. Do you think that's the reason why sending mail is faster for them? Or there are some other reasons involved as well?

@kshitijrana I’ve not worked with the Gmail API. The implementation details are opaque to the consuming client. I was only making an assumption.

What you’ve described seems to me like a synchronous operation, particularly if the HTTP status code that is returned is a 200 as opposed to a 202.

The architectures are likely wildly different, because Gmail is historically newer than Exchange. However, it could simply be that Microsoft didn’t anticipate our use case and saw no need to do any additional compute. It’d be interesting to see what the response times are between the two APIs, though

@sudostack @kshitijrana I've managed to build POC application using the subscription on sentitems folder - $Resource = "users/{user.Id}/mailFolders('sentitems')/messages".
Hoverwer there is one side effect - I get at least 3 notifications for each email sent. Ideally, I'd like to have only a single request, so there should be a new notification type or I must add a filter.

I've tried adding a filter to get notifications only for emails that have my singleValueExtendedProperty. My filter looks like this:

var newSubscription = await graphClient.Subscriptions.Request().WithImmutableId().AddAsync(new Subscription
{
    Resource = $"users/{user.Id}/mailFolders('sentitems')/messages?$filter=singleValueExtendedProperties/Any(ep: ep/id eq 'String {{1f5657a1-f16a-493e-9baf-461f9e2218b7}} Name MyId' and ep/value ne null)",//?$filter=subject eq 'Test'",
    ChangeType = "updated",
    NotificationUrl = "https://6025c15b.ngrok.io/api/values",,
    ClientState = Guid.NewGuid().ToString(),
    ExpirationDateTime = DateTimeOffset.UtcNow + new TimeSpan(0, 0, 5, 0)
});

This filer works:
$"users/{user.Id}/mailFolders('sentitems')/messages?$filter=subject eq 'Test'"
but this don't:
$"users/{user.Id}/mailFolders('sentitems')/messages?$filter=singleValueExtendedProperties/Any(ep: ep/id eq 'String {{1f5657a1-f16a-493e-9baf-461f9e2218b7}} Name MyId' and ep/value ne null)"

I'm adding singleValueExtendedProperty using below code:

var guid = "62a8d197-c880-4ca6-a361-dcad8a24e095";
var email = new Message
{
    Body = new ItemBody
    {
        Content = "Works fine! " + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"),
        ContentType = BodyType.Html,
    },
    Subject = "Test",
    ToRecipients = recipientList,
    Attachments = att
};

var p = new SingleValueLegacyExtendedProperty
{
    Id = $"String {{{guid}}} Name MyId",
    Value = "Test"
};
email.SingleValueExtendedProperties = new MessageSingleValueExtendedPropertiesCollectionPage
{
    p
};

Can I filter subscription using singleValueExtendedProperties?

I dont know why you closing this issue
I think we should get the id after the email sent without making any extra thing
currently we didnt get anything in Rest response

Was this page helpful?
0 / 5 - 0 ratings