Table of contents
- What are adaptive cards?
- Why choose Outlook over Teams?
- Requirements
- Steps to send your first adaptive card
- Registering an adaptive card provider
- About sender e-mail addresses
- About the scope
- About Target urls
- About Card Payload
- Create your first adaptive card
- Including the originator
- Posting a http request
- Put the adaptive into the email message
- Processing data input from adaptive card
- Updating adaptive cards with new content or messages
- After data has been input
- While opening it
- Using this in solutions with a deployment process
What are adaptive cards?
Adaptive cards are messages send via chat or mail that users can interact with. They can contain buttons, dropdown menus, text boxes and much more that your users can interact with. Data entered in an adaptive card can be send back to a database like SharePoint or Dataverse. Furthermore, they can be designed in a way that speak to your users without much effort.
Why choose Outlook over Teams?
Technically speaking it is much easier to send adaptive cards in Microsoft Teams and does not require Premium licenses.
Outlook has some advantages over Teams:
- User Adoption is higher and people still prefer an email over a chat message
- The sender can be chosen and does not have to be “Workflows” like it is in Microsoft Teams
- An adaptive card can wait forever for an answer
- This is its biggest downside as this requires at least one Premium or Process license when processing the input data
Requirements
- The recipient must be an individual, not a group.
- The recipient must be visible on the message. Do not put the recipient in the BCC field.
- The recipient must have a mailbox on Outlook.com or Exchange Online in Office 365.
More on that here: https://learn.microsoft.com/en-us/outlook/actionable-messages/#outlook-version-requirements-for-actionable-messages
Steps to send your first adaptive card
Registering an adaptive card provider
- Use this portal to register your adaptive card (register new provider): https://outlook.office.com/connectors/oam/publish
As of January 2025 there is known issue while accessing the connector portal. To mitigate this simply open https://outlook.office.com/mail in separate tab. Then try again accessing the portal in its own tab.
- Add mandatory details
- Send to approval
Once the request is approved it cannot be updated easily.
More here: https://learn.microsoft.com/en-us/outlook/actionable-messages/actionable-messages-faq
About sender e-mail addresses
Here you should add all email addresses from which the message will come from. If you are using a user account that has multiple mail addresses or where the UPN is different from the E-Mail address, add all addresses. Or in case you are sending the E-Mail from a shared mailbox, add that address too.
About the scope
There is different scopes for your adaptive cards and it makes sense to carefully take a look at the options:
- Test Users - Only use this for playing around or developing, you will have to specify the recipient email addresses. This will be auto approved.
- Organization - Use this if you only want to send adaptive cards within your tenant (and all its domains)
- Global or Exchange Admins can approve your request here: https://outlook.office.com/connectors/oam/admin
- If you need to update this, you have to create a new provider. Since its internally approved, you don’t have to plan ahead here.
- Global - Use this if you want to send adaptive cards within AND outside of your tenant (be aware of the requirements)
- If you need to update this, you either have to register a new provider or ask for an update by reaching out to: onboardoam@microsoft.com
About Target urls
All endpoints that send data via a HTTP in your card need to registered. This can be a Power Automate Flow or custom endpoints from an internal service or API.
You probably want to set up a test scope while developing because you have to specify the endpoints you are accessing from your card.
If you use the post action in your adaptive card you should add all urls that you will post to. You can also use regex. All URLs have to be https:// enabled. If you are using a “When a HTTP request is received” trigger to collect data from the card with Power Automate you need to add the trigger url, but without the sig-part of it.
This is an example url from the trigger and contains all parameters:
https://prod35.logic.azure.com:443/workflows/91239812903819283091823/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=34672t3764f23guzk4g237orezf9w8osidfjsfs
Workflow id (right after workflows/) and signature (sig=) are two of the things you should never share online, so keep them as safe as possible. For registering your card, do not include the signature. The signature is only necessary for the HTTP Post action within your card later.
About Card Payload
Usually you would add the complete adaptive card JSON code(s). As of January 2025, there is a known issue when the payload is either too large or contains specific elements. The website then return an HTTP Error 500. Microsoft recommends pasting a very plain payload and sending the actual payload as an attachment to onboardoam@microsoft.com mentioning the originator id.
Create your first adaptive card
Im not going into details about how to design an adaptive card, but I recommend using the usual adaptive card designer https://adaptivecards.io/designer/ and then switch to the host “Outlook Actionable Messages”.
You can also design your cards here: https://amdesigner.azurewebsites.net/
A quick note about versions. I have made the experience that the versions play a huge role in the functionality of the adaptive card. If you fine with using lower versions with less functionality then use v1.0 otherwise you can use whatever is the highest supported. As of January 2025 that is v1.4. Read more here: https://learn.microsoft.com/en-us/outlook/actionable-messages/actionable-messages-faq#upgrading-to-adaptive-card-14-and-above
Including the originator
It is crucial to include the originator id when you registered the card. Exchange will use the combination of the senders address and the originator to validate. Add the originator manually to your code on the highest level in the adaptive card json. The highest level is usually the part where the version and schema are mentioned.
{
"type": "AdaptiveCard",
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
"version": "1.0",
"originator":"ADD THE ID HERE",
"body":[]
}
Posting a http request
Returning data from the card to a data table is easily done in Microsoft Teams, but is a little more zesty in Outlook. In this sample we have a field with the id “Comment”. Use the id for any given input that you want to handover in the HTTP request. You might need to escape quotes.
{
"type": "ActionSet",
"id": "1e77f639-e5a8-320f-c6de-4291227db6b3",
"actions": [
{
"type": "Action.Http",
"id": "1ca3a888-ebfb-1feb-064b-928960616e52",
"title": "Submit",
"method": "POST",
"url": "https://prod35.logic.azure.com:443/workflows/91239812903819283091823/triggers/manual/paths/invoke?api-version=2016-06-01&sp=%2Ftriggers%2Fmanual%2Frun&sv=1.0&sig=34672t3764f23guzk4g237orezf9w8osidfjsfs",
"body": "{comment: {{Comment.value}}}"
}
]
}
Put the adaptive into the email message
The adaptive card json has to be placed within the script tags as well as the head of the html. Within you head include also the charset parameter to make special characters display correctly.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<script type="application/adaptivecard+json">
{YOUR ADAPTIVE CARD JSON}
</script>
</head>
<body>
FURTHER HTML CONTENT IN MAIL
</body>
</html>
Processing data input from adaptive card
If you are working with Power Automate you have to use the trigger “When an HTTP request is received”. This is the part where a per user or a process license is required.
- Authentication set to anyone makes things a lot easier. I believe that other methods would also work, but I have not tried yet.
- Next, set a JSON schema. This is a parsed version of the body you are sending from the adaptive card to the flow. This will also make it easier to further work with the parameters later in your flow.
- Continue adding actions to your flow
- At least once in your flow you should use the “HTTP - Response” action to update the adaptive card to display something like a thank you or confirmed message.
You will notice that you after you save your flow for the first time, the trigger url gets generated. This means that you can only do the registration (organization or global) after you have created the complete solution. Again, in this case it makes sense to start with the test users scope.
You will receive a url after the flow has been saved and turned on
use the url for the target urls when registering, leave out the sig= part like this
In the adaptive card use the url including the sig part
Obviously, you can also use custom endpoints that accept post requests.
Updating adaptive cards with new content or messages
After data has been input
Use the HTTP response action to answer to the http request send from the adaptive card. The body you are sending back to the card is basically another adaptive card with all the values you want to display to the user.
While opening it
You can use the same flow as you already created for processing input data. Just remember that the JSON schema has to be the same.
Just like approvals you might have a workflow that sends that email to multiple users at the same time. One of them might answer before and therefore, you don’t want the others to reply after that too. Or you want to provide time sensitive information like flight information, then you would want the card to update when the user opens it. You can do this by using the autoInvokeAction in your adaptive card json outside of the body array.
These requests need an answer within 2 seconds, so only request for the most relevant data.
"autoInvokeAction": {
"headers": [
{
"name": "Authorization",
"value": ""
},
{
"name": "Content-Type",
"value": "application/json"
}
],
"method": "POST",
"type": "Action.Http",
"url": "ENDPOINTURL",
"body": "{\"updatedfieldormessage\": \"anydatayouwant\"}"
}
Using this in solutions with a deployment process
A few thoughts about working with solutions:
- When exporting and importing your flow into a new environment, the http trigger will have a new url in the production environment once imported. Take this into consideration when registering you provider.
- Store the originator id as well as the endpoint url(s) in environment variables or if necessary in Azure Key Vault variables for more security.
Thanks for reading! 💕