Send-FilesViaEmail.psm1

function Send-FilesViaEmail {
  <#
  .SYNOPSIS
  Sends one email with one or more file attachments through Microsoft Graph.

  .DESCRIPTION
  A variant of Send-FileViaEmail that takes any number of files. Authenticates with client
  credentials and posts users/{from}/sendMail. Each attachment is named after its file.

  .PARAMETER Files
  One path or an array of paths. Every file is attached to the same message.

  .PARAMETER Cfg
  mail.from, mail.to (one address or an array), mail.subject, optional mail.body (plain text),
  msgraph.tenant_id, msgraph.client_id, msgraph.client_secret.

  .PARAMETER ContentType
  MIME type recorded on every attachment. Default application/octet-stream.
  #>

  [CmdletBinding()]
  param(
    [Parameter(Mandatory, Position = 0)][string[]]$Files,
    [Parameter(Mandatory, Position = 1)]$Cfg,
    [Parameter(Position = 2)][string]$ContentType = 'application/octet-stream',
    [ValidateRange(1, 3600)][int]$TimeoutSec = 100
  )
  $attachments = @(foreach ($file in $Files) {
    $path = (Resolve-Path -LiteralPath $file).Path
    @{
      '@odata.type' = '#microsoft.graph.fileAttachment'
      name = Split-Path -Leaf $path
      contentType = $ContentType
      contentBytes = [Convert]::ToBase64String([IO.File]::ReadAllBytes($path))
    }
  })
  $token = Invoke-RestMethod -Method Post -TimeoutSec $TimeoutSec `
    -Uri ("https://login.microsoftonline.com/{0}/oauth2/v2.0/token" -f $Cfg.msgraph.tenant_id) `
    -Body @{
      client_id = $Cfg.msgraph.client_id
      scope = 'https://graph.microsoft.com/.default'
      client_secret = $Cfg.msgraph.client_secret
      grant_type = 'client_credentials'
    }
  $message = @{
    subject = $Cfg.mail.subject
    toRecipients = @($Cfg.mail.to | ForEach-Object { @{ emailAddress = @{ address = $_ } } })
    attachments = $attachments
  }
  if ($Cfg.mail.body) { $message.body = @{ contentType = 'Text'; content = [string]$Cfg.mail.body } }
  Invoke-RestMethod -Method Post -TimeoutSec $TimeoutSec -ContentType 'application/json' `
    -Uri ("https://graph.microsoft.com/v1.0/users/{0}/sendMail" -f $Cfg.mail.from) `
    -Headers @{ Authorization = "Bearer $($token.access_token)" } `
    -Body (@{ message = $message } | ConvertTo-Json -Depth 6)
}
Export-ModuleMember -Function Send-FilesViaEmail