also the Cloud Voicemail service has an Audio transcription service which is reasonably accurate.
Accessing Voice Mails programmatically
Accessing these voice messages is pretty easy they are all just messages in your mailbox (usually the Inbox but they can have been moved to other folders) that have a MessageClass of IPM.Note.Microsoft.Voicemail.UM.CA ref https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxoum/102b3a8b-1aad-4f29-90a3-998262d9fa26 . By default in the Exchange Mailbox there is a WellKnownFolder (in this instance its a Search Folder) called VoiceMail that can then be used in either the Microsoft Graph or EWS to return these voice mail messages. eg for the Microsoft Graph your request should look something like
https://graph.microsoft.com/v1.0/users('gscales@datarumble.com')/mailFolders/voicemail/messages ?$expand=SingleValueExtendedProperties( $filter=Id%20eq%20'Integer%20%7B00020328-0000-0000-C000-000000000046%7D%20Id%200x6801'%20 or%20Id%20eq%20'String%20%7B00020386-0000-0000-C000-000000000046%7D%20Name%20X-VoiceMessageConfidenceLevel'%20 or%20Id%20eq%20'String%20%7B00020386-0000-0000-C000-000000000046%7D%20Name%20X-VoiceMessageTranscription')& $top=100&$select=Subject,From,Body,IsRead,Id,ReceivedDateTime
In my request I'm including the following 3 extended properties that the Teams client also needs to have (actually creating a voice message without these properties will break the voicemail section of the Teams client which is a bug on the Microsoft side and one which 3rd party Migration vendors will need to watch out for). The three properties are firstly
PidTagVoiceMessageDuration - https://docs.microsoft.com/en-us/openspecs/exchange_server_protocols/ms-oxoum/970d4c1c-dcc5-44d2-aab3-16e37805b953 which is the length of the voicemail in seconds. A quick PowerShell trick of getting the length of the voicemail from an Mp3 file is to use the Shell Applicaiton eg
$shell = New-Object -COMObject Shell.Application $folder = Split-Path $Mp3FileName $file = Split-Path $Mp3FileName -Leaf $shellfolder = $shell.Namespace($folder) $shellfile = $shellfolder.ParseName($file) $dt = [DateTime]::ParseExact($shellfolder.GetDetailsOf($shellfile, 27), "HH:mm:ss",[System.Globalization.CultureInfo]::InvariantCulture); $dt.TimeOfDay.TotalSeconds
The other two properties are Internet Header properties so could be either returned by requesting all the Internet Headers on the message or using the Extended properties definition
X-VoiceMessageTranscription - currently undocumented but seems to contain the transcription of the voice message (The transcription is also included in the Body of the Message)
and
X-VoiceMessageConfidenceLevel - currently undocumented
I've put together a script which is posted here that will return Voicemail from a Mailbox including the above information using the Microsoft Graph along with the ADAL library for authentication. The script is located https://github.com/gscales/Powershell-Scripts/blob/master/VoiceMailGraph.ps1 eg in action it looks like
Get-VoiceMail -MailboxName e5tmp5@datarumble.com | select @{n="Sender";e={$_.from.emailAddress.address}},Subject,PidTagVoiceMessageDuration,x* |ft
Which will give an output like
To run this type of script will require an App registration with at least Mail.Read or Mail.Read.Shared if you want to access mailboxes other then your own.
Sending Voice Mails programmatically
To Send a VoiceMail message using the Microsoft Graph or EWS is just a matter of sending a Message and setting the ItemClass to IPM.Note.Microsoft.Voicemail.UM.CA, attach the MP3 file and
POST https://graph.microsoft.com/v1.0/users('gscales@datarumble.com')/sendmail HTTP/1.1 "Message" : { "Subject": "Voice Mail (27 seconds)" ,"Sender":{ "EmailAddress":{ "Name":"gscales@datarumble.com", "Address":"gscales@datarumble.com" }} ,"Body": { "ContentType": "HTML", "Content": "<html><head>...</html>" } ,"ToRecipients": [ { "EmailAddress":{ "Name":"e5tmp5@datarumble.com", "Address":"e5tmp5@datarumble.com" }} ] , "Attachments": [ { "@odata.type": "#Microsoft.OutlookServices.FileAttachment", "Name": "audio.mp3", "ContentBytes": "..." } ] ,"SingleValueExtendedProperties": [ { "id":"String 0x001A", "Value":"IPM.Note.Microsoft.Voicemail.UM.CA" } ,{ "id":"Integer {00020328-0000-0000-c000-000000000046} Id 0x6801", "Value":"27" } ,{ "id":"String {00020386-0000-0000-C000-000000000046} Name X-VoiceMessageConfidenceLevel", "Value":"high" } ,{ "id":"String {00020386-0000-0000-C000-000000000046} Name X-VoiceMessageTranscription", "Value":"one two three" }, ,{ "id":"String 0x6805", "Value":"audio.mp3" } ] } ,"SaveToSentItems": "true" }
Depending on where you got the Mp3 your sending as a voice message you will need to do the transcription yourself eg Azure cognitive services can be used to do this https://docs.microsoft.com/en-us/azure/cognitive-services/speech-service/speech-to-text . Or if you want to generate a MP3 from some text you have using PowerShell you can use this cool script that Adam Bertram posted https://mcpmag.com/articles/2019/05/23/text-to-speech-azure-cognitive-services.aspx . I've created a script that you can use to Send a Voicemail using the Microsoft Graph API using the ADAL libraray for Authentication https://github.com/gscales/Powershell-Scripts/blob/master/VoiceMailGraph.ps1 . To use this try something like the following
Send-VoiceMail -MailboxName gscales@datarumble.com -ToAddress e5tmp5@datarumble.com -Mp3FileName C:\temp\SampleAudio_0.4mb.mp3 -Transcription "one two three"
When sending a Voicemail it includes the following HTML table in a Message that contains the sending users personal information eg
To fill out this information in the script I'm making another graph call to look at the users information based on the email address (technically you could use the /me if you never going to send as another user). So the script also makes the following Graph query to get this information
https://graph.microsoft.com/v1.0/users?$filter=mail%20eq%20'gscales@datarumble.com'&$Select=displayName,businessPhones,mobilePhone,mail,jobTitle,companyName
To Send a Message will requires an App Registration with Mail.Send as well as User.Read to be able to read the directory properties required to fill out the Body of the Message with the sending users phone, title and company information.
Doing the same in EWS
You can do the same as above using EWS, instead of the userdetail query the same information can be retrieved using the ResolveName operation in EWS. I've put a sample module for geting and sending voicemail using EWS on Github here informationhttps://github.com/gscales/Powershell-Scripts/blob/master/VoiceMailEWS.ps1