Introduction

Hi guys, sometimes we may come across the scenario where we want to copy email (.eml file) from Office o365 to Sharepoint library. This article will help you to solve this scenario.
We have to follow these steps to achieve the above requirement:
  • Read emails from the Office O365 account.
  • Extract the emails to the local directory in .eml file format.
  • Upload the extracted .eml file to SharePoint library files.
  • Moved the read emails to another folder in the o365 account from the inbox.
  • Finally, delete the extracted files from local directory
We can execute the above steps with the help of:
  • Using Powershell Script
  • Using MS Flow
Before starting with any methods, create one folder inside inbox in office o365 account and one library(Test) in SharePoint online to upload the .eml file.
Copy Email From Office 365 To SharePoint Library

Using PowerShell Script

The PowerShell script requires the following library files.
It requires EWS Managed API 2.2, which can be download and install from here
It requires a SharePoint Online SDK, which can be downloaded and install from here.
Store the credentials of office 365 account and SharePoint online account in the files and read the credentials in the script from the same files. To create and use the credentials in the script in a file and another way, refer my article Passing Credentials in SharePoint Online Using PowerShell
Firstly, import and refer the downloaded library files in your script like this.
  1. #Add dll files
  2. Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
  3. #Load SharePoint CSOM Assemblies
  4. Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
  5. Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
Read the emails from office o365 account:
  1. <#
  2. This function is used to read emails from particular emails
  3. #>
  4. Function ReadEmails() {
  5. param(
  6. [Parameter(Mandatory = $true)] $SiteURL,
  7. [Parameter(Mandatory = $true)] $USER_DEFINED_FOLDER_IN_MAILBOX
  8. )
  9. If(!(test-path $exportPath))
  10. {
  11. Write-Host "Path doesn't exist $($exportPath), Hence creating the path." -f Red
  12. New-Item -ItemType Directory -Force -Path $exportPath
  13. }
  14. $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
  15. $service.Credentials = New-Object System.Net.NetworkCredential -ArgumentList $fileCred.UserName, $fileCred.Password
  16. $service.URL = New-Object Uri("https://outlook.office365.com/EWS/Exchange.asmx")
  17. # create Property Set to include body and header of email
  18. $PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
  19. # set email body to text
  20. $PropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text;
  21. # Set how many emails we want to read at a time
  22. $numOfEmailsToRead = 100
  23. # Index to keep track of where we are up to. Set to 0 initially.
  24. $index = 0
  25. # Do/while loop for paging through the folder
  26. do {
  27. # Set what we want to retrieve from the folder. This will grab the first $pagesize emails
  28. $view = New-Object Microsoft.Exchange.WebServices.Data.ItemView($numOfEmailsToRead, $index)
  29. # Retrieve the data from the folder
  30. $findResults = $service.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox, $view)
  31. foreach ($item in $findResults.Items) {
  32. # load the additional properties for the item
  33. $item.Load($propertySet)
  34. # Output the results
  35. $msgProperty = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::MimeContent)
  36. $email = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($service, $item.Id, $msgProperty)
  37. $fileName = "$($item.Subject)_$($item.DateTimeReceived)"
  38. $subject = Remove-InvalidFileNameChars($fileName)
  39. $filePath = "$($exportPath)$($subject).eml";
  40. Write-Host "File Name:"$filePath
  41. # Export the file into .eml format
  42. Export-EMLFile $filePath $email
  43. $fileSize = 0;
  44. $currentFile = New-Object System.IO.FileInfo($filePath);
  45. #while ($fileSize -ilt $currentFile.Length)#check size is stable or increased
  46. #{
  47. #$fileSize = $currentFile.Length; #get current size
  48. #Start-Sleep -s 60
  49. #$currentFile.Refresh(); #refresh length value
  50. #}
  51. # moved the file to destination folder in office 365 email
  52. Move-Email $service $item $USER_DEFINED_FOLDER_IN_MAILBOX $fileName
  53. }
  54. # Increment $index to next block of emails
  55. $index += $numOfEmailsToRead
  56. } while ($findResults.MoreAvailable) # Do/While there are more emails to retrieve
  57. #Upload the file to library after exporting it
  58. }
We will check and removed the invalid character in email subject with underscore (_).
  1. #Removes invalid Characters for file names from a string input and outputs the clean string
  2. #Similar to VBA CleanString() Method
  3. #Currently set to replace all illegal characters with a hyphen (_)
  4. Function Remove-InvalidFileNameChars {
  5. param(
  6. [Parameter(Mandatory = $true, Position = 0)]
  7. [String]$Name
  8. )
  9. return [RegEx]::Replace($Name, "[{0}]" -f ([RegEx]::Escape([String][System.IO.Path]::GetInvalidFileNameChars())), '_')
  10. }
Export all the emails from inbox to local directory:
  1. <#
  2. This function is used to export the email to .eml files
  3. #>
  4. Function Export-EMLFile() {
  5. param(
  6. [Parameter(Mandatory = $true, Position = 0)]$filePath,
  7. [Parameter(Mandatory = $true, Position = 1)]$email
  8. )
  9. try {
  10. Write-Host "Extracting Email file"
  11. $fs = New-Object System.IO.FileStream($filePath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write)
  12. $fs.Write($email.MimeContent.Content, 0, $email.MimeContent.Content.Length)
  13. }
  14. catch {
  15. Write-host -Message $_.Exception.Message
  16. }
  17. }
Upload the extracted .eml files to SharePoint library with this code.
  1. <#
  2. This function is used to upload the files into sharepoint library
  3. #>
  4. Function Upload-MultipleFile-To-Library() {
  5. param(
  6. [Parameter(Mandatory = $true)][String]$siteUrl,
  7. [Parameter(Mandatory = $true)][String]$libraryName,
  8. [Parameter(Mandatory = $true)]$folder
  9. )
  10. $Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($spfileCred.UserName, $spfileCred.Password)
  11. #Set up the context
  12. $Context = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
  13. $Context.Credentials = $Cred
  14. #Retrieve list
  15. $List = $Context.Web.Lists.GetByTitle($libraryName)
  16. $Context.Load($List)
  17. $Context.ExecuteQuery()
  18. Write-Host "Folder" $folder
  19. # Upload file
  20. Foreach ($File in (Get-ChildItem $folder)) {
  21. Write-Host "Uploading File......$($File.FullName)"
  22. $FileStream = New-Object IO.FileStream($File.FullName, [System.IO.FileMode]::Open)
  23. $FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
  24. $FileCreationInfo.Overwrite = $true
  25. $FileCreationInfo.ContentStream = $FileStream
  26. $FileCreationInfo.URL = $File
  27. $Upload = $List.RootFolder.Files.Add($FileCreationInfo)
  28. $Context.Load($Upload)
  29. $Context.ExecuteQuery()
  30. $File.Delete()
  31. }
  32. }
Move the read emails from inbox to another folder (i.e Moved folder)
  1. <#
  2. This function is used to moved the email from inbox to another folder in office 365
  3. #>
  4. Function Move-Email() {
  5. param
  6. (
  7. [Parameter(Mandatory = $true)]$service,
  8. [Parameter(Mandatory = $true)]$Item,
  9. [Parameter(Mandatory = $true)]$USER_DEFINED_FOLDER_IN_MAILBOX,
  10. [Parameter(Mandatory = $true)]$fileName
  11. )
  12. $FolderId = @();
  13. $FolderView = new-object -TypeName Microsoft.Exchange.WebServices.Data.FolderView -ArgumentList (100)
  14. $FolderView.Traversal = [Microsoft.Exchange.Webservices.Data.FolderTraversal]::Deep
  15. $SearchFilter = new-object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo -ArgumentList ([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$USER_DEFINED_FOLDER_IN_MAILBOX)
  16. $FindFolderResults = $service.FindFolders([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$SearchFilter,$FolderView)
  17. if($FindFolderResults.Id) {
  18. Write-host "Moving File $($fileName) from Inbox to $($USER_DEFINED_FOLDER_IN_MAILBOX)" -ForegroundColor Yellow
  19. $FolderId += $FindFolderResults.Id
  20. }
  21. $Message = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($service,$Item.Id)
  22. $Message.Move($FolderId[0])
  23. }
Delete all the .eml files from directory with this line.
  1. Foreach ($File in (Get-ChildItem $folder)) {
  2. Write-Host "Deleting File......$($File.FullName)"
  3. $File.Delete()
  4. }
The complete powershell script will look like this:
  1. <#
  2. This script will perform the following fuction,
  3. -> It will export the email from o365 mail to .eml file on local computer directory.
  4. -> Once file is available in local directory it will upload the .eml file into SharePoint Library.
  5. -> It will delete the files from local directory.
  6. -> Finally, It will moved the files from 'Inbox' to another folder in o365 mail box.
  7. ***************************************************************************************************
  8. Prerequisites
  9. ***************************************************************************************************
  10. 1 - The script requires EWS Managed API 2.2, which can be downloaded here:
  11. https://www.microsoft.com/en-us/download/details.aspx?id=42951
  12. 2 - The script requires SharePoint Online SDK, Which can be downloaded here:
  13. https://www.microsoft.com/en-in/download/details.aspx?id=42038
  14. 3 - TargetFolder has to be created previous to run the Script
  15. 4 - Source and Target folders have to be unique names. No repeated folders in subfolders.
  16. ***************************************************************************************************
  17. Required Parameters
  18. ***************************************************************************************************
  19. 1. $credPath
  20. 2. $fileCred
  21. 3. $spCredPath
  22. 4. $spfileCred
  23. 5. $SiteURL
  24. 6. $libraryName
  25. 7. $exportPath
  26. 8. $USER_DEFINED_FOLDER_IN_MAILBOX
  27. ***************************************************************************************************
  28. Created by : Arvind Kushwaha
  29. E-mail : arvind.kushwaha
  30. Created Date : 22-05-2020
  31. version : 1.0
  32. ***************************************************************************************************
  33. #>
  34. #Add dll files
  35. Import-Module -Name "C:\Program Files\Microsoft\Exchange\Web Services\2.2\Microsoft.Exchange.WebServices.dll"
  36. #Load SharePoint CSOM Assemblies
  37. Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.dll"
  38. Add-Type -Path "C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\16\ISAPI\Microsoft.SharePoint.Client.Runtime.dll"
  39. #Pass Credentials
  40. $credPath = "D:\Arvind\safe\secret.txt"
  41. $fileCred = Import-Clixml -path $credpath
  42. $spCredPath = 'Path to SharePoint Online Account Credentials Files'
  43. $spfileCred = Import-Clixml -path $spCredPath
  44. $SiteURL = "Your Site Url"
  45. $libraryName = "Your library Name"
  46. $exportPath = "D:\Arvind\logs\qc\"
  47. $USER_DEFINED_FOLDER_IN_MAILBOX = "Moved"
  48. $folder = $exportPath
  49. <#
  50. call the function
  51. #>
  52. #ReadEmails $SiteURL $USER_DEFINED_FOLDER_IN_MAILBOX
  53. Upload-MultipleFile-To-Library $SiteURL $libraryName $folder
  54. <#
  55. This function is used to read emails from particular emails
  56. #>
  57. Function ReadEmails() {
  58. param(
  59. [Parameter(Mandatory = $true)] $SiteURL,
  60. [Parameter(Mandatory = $true)] $USER_DEFINED_FOLDER_IN_MAILBOX
  61. )
  62. If(!(test-path $exportPath))
  63. {
  64. Write-Host "Path doesn't exist $($exportPath), Hence creating the path." -f Red
  65. New-Item -ItemType Directory -Force -Path $exportPath
  66. }
  67. $service = New-Object Microsoft.Exchange.WebServices.Data.ExchangeService
  68. $service.Credentials = New-Object System.Net.NetworkCredential -ArgumentList $fileCred.UserName, $fileCred.Password
  69. $service.URL = New-Object Uri("https://outlook.office365.com/EWS/Exchange.asmx")
  70. # create Property Set to include body and header of email
  71. $PropertySet = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.BasePropertySet]::FirstClassProperties)
  72. # set email body to text
  73. $PropertySet.RequestedBodyType = [Microsoft.Exchange.WebServices.Data.BodyType]::Text;
  74. # Set how many emails we want to read at a time
  75. $numOfEmailsToRead = 100
  76. # Index to keep track of where we are up to. Set to 0 initially.
  77. $index = 0
  78. # Do/while loop for paging through the folder
  79. do {
  80. # Set what we want to retrieve from the folder. This will grab the first $pagesize emails
  81. $view = New-Object Microsoft.Exchange.WebServices.Data.ItemView($numOfEmailsToRead, $index)
  82. # Retrieve the data from the folder
  83. $findResults = $service.FindItems([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::Inbox, $view)
  84. foreach ($item in $findResults.Items) {
  85. # load the additional properties for the item
  86. $item.Load($propertySet)
  87. # Output the results
  88. $msgProperty = New-Object Microsoft.Exchange.WebServices.Data.PropertySet([Microsoft.Exchange.WebServices.Data.EmailMessageSchema]::MimeContent)
  89. $email = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($service, $item.Id, $msgProperty)
  90. $fileName = "$($item.Subject)_$($item.DateTimeReceived)"
  91. $subject = Remove-InvalidFileNameChars($fileName)
  92. $filePath = "$($exportPath)$($subject).eml";
  93. Write-Host "File Name:"$filePath
  94. # Export the file into .eml format
  95. Export-EMLFile $filePath $email
  96. $fileSize = 0;
  97. $currentFile = New-Object System.IO.FileInfo($filePath);
  98. #while ($fileSize -ilt $currentFile.Length)#check size is stable or increased
  99. #{
  100. #$fileSize = $currentFile.Length; #get current size
  101. #Start-Sleep -s 60
  102. #$currentFile.Refresh(); #refresh length value
  103. #}
  104. # moved the file to destination folder in office 365 email
  105. Move-Email $service $item $USER_DEFINED_FOLDER_IN_MAILBOX $fileName
  106. }
  107. # Increment $index to next block of emails
  108. $index += $numOfEmailsToRead
  109. } while ($findResults.MoreAvailable) # Do/While there are more emails to retrieve
  110. #Upload the file to library after exporting it
  111. }
  112. #Removes invalid Characters for file names from a string input and outputs the clean string
  113. #Similar to VBA CleanString() Method
  114. #Currently set to replace all illegal characters with a hyphen (_)
  115. Function Remove-InvalidFileNameChars {
  116. param(
  117. [Parameter(Mandatory = $true, Position = 0)]
  118. [String]$Name
  119. )
  120. return [RegEx]::Replace($Name, "[{0}]" -f ([RegEx]::Escape([String][System.IO.Path]::GetInvalidFileNameChars())), '_')
  121. }
  122. #checked file is locked or not
  123. Function IsFileLocked() {
  124. param
  125. (
  126. [Parameter(Mandatory = $true, Position = 0)][System.IO.FileStream]$fileInfo
  127. )
  128. [System.IO.FileStream]$stream = $null;
  129. try {
  130. $stream = $fileInfo.Open([System.IO.FileMode]::Open, [System.IO.FileAccess]::Write, [System.IO.FileShare]::None);
  131. }
  132. catch {
  133. return $true;
  134. }
  135. #file is not locked
  136. return $false;
  137. }
  138. <#
  139. This function is used to export the email to .eml files
  140. #>
  141. Function Export-EMLFile() {
  142. param(
  143. [Parameter(Mandatory = $true, Position = 0)]$filePath,
  144. [Parameter(Mandatory = $true, Position = 1)]$email
  145. )
  146. try {
  147. Write-Host "Extracting Email file"
  148. $fs = New-Object System.IO.FileStream($filePath, [System.IO.FileMode]::Create, [System.IO.FileAccess]::Write)
  149. $fs.Write($email.MimeContent.Content, 0, $email.MimeContent.Content.Length)
  150. }
  151. catch {
  152. Write-host -Message $_.Exception.Message
  153. }
  154. }
  155. <#
  156. This function is used to upload the files into sharepoint library
  157. #>
  158. Function Upload-MultipleFile-To-Library() {
  159. param(
  160. [Parameter(Mandatory = $true)][String]$siteUrl,
  161. [Parameter(Mandatory = $true)][String]$libraryName,
  162. [Parameter(Mandatory = $true)]$folder
  163. )
  164. $Cred = New-Object Microsoft.SharePoint.Client.SharePointOnlineCredentials($spfileCred.UserName, $spfileCred.Password)
  165. #Set up the context
  166. $Context = New-Object Microsoft.SharePoint.Client.ClientContext($siteUrl)
  167. $Context.Credentials = $Cred
  168. #Retrieve list
  169. $List = $Context.Web.Lists.GetByTitle($libraryName)
  170. $Context.Load($List)
  171. $Context.ExecuteQuery()
  172. Write-Host "Folder" $folder
  173. # Upload file
  174. Foreach ($File in (Get-ChildItem $folder)) {
  175. Write-Host "Uploading File......$($File.FullName)"
  176. $FileStream = New-Object IO.FileStream($File.FullName, [System.IO.FileMode]::Open)
  177. $FileCreationInfo = New-Object Microsoft.SharePoint.Client.FileCreationInformation
  178. $FileCreationInfo.Overwrite = $true
  179. $FileCreationInfo.ContentStream = $FileStream
  180. $FileCreationInfo.URL = $File
  181. $Upload = $List.RootFolder.Files.Add($FileCreationInfo)
  182. $Context.Load($Upload)
  183. $Context.ExecuteQuery()
  184. $File.Delete()
  185. }
  186. }
  187. <#
  188. This function is used to moved the email from inbox to another folder in office 365
  189. #>
  190. Function Move-Email() {
  191. param
  192. (
  193. [Parameter(Mandatory = $true)]$service,
  194. [Parameter(Mandatory = $true)]$Item,
  195. [Parameter(Mandatory = $true)]$USER_DEFINED_FOLDER_IN_MAILBOX,
  196. [Parameter(Mandatory = $true)]$fileName
  197. )
  198. $FolderId = @();
  199. $FolderView = new-object -TypeName Microsoft.Exchange.WebServices.Data.FolderView -ArgumentList (100)
  200. $FolderView.Traversal = [Microsoft.Exchange.Webservices.Data.FolderTraversal]::Deep
  201. $SearchFilter = new-object -TypeName Microsoft.Exchange.WebServices.Data.SearchFilter+IsEqualTo -ArgumentList ([Microsoft.Exchange.WebServices.Data.FolderSchema]::DisplayName,$USER_DEFINED_FOLDER_IN_MAILBOX)
  202. $FindFolderResults = $service.FindFolders([Microsoft.Exchange.WebServices.Data.WellKnownFolderName]::MsgFolderRoot,$SearchFilter,$FolderView)
  203. if($FindFolderResults.Id) {
  204. Write-host "Moving File $($fileName) from Inbox to $($USER_DEFINED_FOLDER_IN_MAILBOX)" -ForegroundColor Yellow
  205. $FolderId += $FindFolderResults.Id
  206. }
  207. $Message = [Microsoft.Exchange.WebServices.Data.EmailMessage]::Bind($service,$Item.Id)
  208. $Message.Move($FolderId[0])
  209. }

Using MS Flow

Open SharePoint online account and navigate to power automate to create the flow.
Copy Email From Office 365 To SharePoint Library
Now click on Create and select Automated flow.
Copy Email From Office 365 To SharePoint Library
Write the name of flow and choose the flow trigger action i.e When a new email arrives(V3)
Copy Email From Office 365 To SharePoint Library
Select the appropriate folder from where the email will be pulled out. (i.e Inbox)
Copy Email From Office 365 To SharePoint Library
Choose another action by clicking on the plus sign (+) or click on New Step, and select Export email(V2).
Copy Email From Office 365 To SharePoint Library
Copy Email From Office 365 To SharePoint Library
Choose another action i.e Create file and configure the action in this way.
*Site Address : The Url of the SharePoint site
*Folder Path: /Document Library Name
*File Name: Write this expression in this field concat(triggerBody()?['Subject'],triggerBody()?['DateTimeReceived'])
*File Content: Body of Email.
Copy Email From Office 365 To SharePoint Library
Finally, move the email from the inbox to another folder (Moved) with Move email(v2) action.
Copy Email From Office 365 To SharePoint Library
Copy Email From Office 365 To SharePoint Library

Test the flow

Send an email to office 365 account for which flow is configured. (i.e I had configured for my account.)
Copy Email From Office 365 To SharePoint Library
The flow will trigger as soon as you send an email to our configured account and will look like this
Copy Email From Office 365 To SharePoint Library
Check the moved folder which contains the test email.
Copy Email From Office 365 To SharePoint Library
Now, check the SharePoint library which contains the .eml files.
Copy Email From Office 365 To SharePoint Library

Conclusion

In these articles, we have seen how to copy the email from an Office O365 account and upload it into the SharePoint library with PowerShell script and MS flow.