Viimeisin päivitys: 2026-03-02
Lähetä sähköposteja Opterista Microsoft 365:n avulla
Tässä artikkelissa
Jos käytät sähköpostipalveluna Microsoft 365:tä, sinun on todennettava Opter rekisteröimällä se sovelluksena Azuressa.
Sovelluksen rekisteröinti Azureen voidaan tehdä PowerShell-skriptillä, joka on saatavilla koodiesimerkkinä alla. Syy siihen, miksi skriptiä ei voi suorittaa päivityksen yhteydessä, on se, että skriptin suorittajalla on oltava oikeus muuttaa Microsoft Entra ID:tä (entinen Azure Active Directory) ja hänellä on oltava organisaatiosi Microsoft 365:n järjestelmänvalvojan oikeudet, mitä Opter ei ole. Skripti tekee tarvittavat asetukset Entra ID:hen ja Exchangeen. Kun skripti on suoritettu, toimiston asetusten välilehdelle Palvelimet on syötettävä joitakin tietoja.
Alla oleva skripti saattaa vaatia säätöjä, jotta se toimii juuri sinun ympäristössäsi.
Vaihe 1: Selvitä lähettäjän osoitteet
Selvitä, mitä sähköpostiosoitteita käytätte Opterin sähköpostiviestien lähettämiseen. Voit määrittää käyttämäsi sähköpostiosoitteet jo skriptiä suorittaessasi. Muussa tapauksessa sinun on tehtävä se manuaalisesti Exchange-ohjelmassa jälkikäteen (katso alla).
-
Ensisijainen osoite: Löytyy kentästä S-posti välilehdellä Yleinen toimistoasetuksissa.
-
Alueiden osoitteet (jos käytätte niitä): Löytyy kentästä S-posti välilehdellä Yleinen alueiden kohdalla.
-
Laskutus- ja muut talousviestit osoitteeseen: Löytyy kentästä S-posti välilehdellä Laskun yksityiskohdat toimistoasetuksissa tai alueilla (jos käytät sitä).
Opterin järjestelmän omistaja tietää, mitä lähettäjän osoitteita Opter käyttää. Lisätietoa: Vaihtoehtoiset sähköpostiosoitteet.
Vaihe 2: Avaa Powershell
Skriptin on suoritettava PowerShell 7:ssä tai uudemmassa versiossa, ei Windows PowerShell ISE:ssä. Napsauta Windowsin Käynnistä-valikkoa ja hae sanaa ”powershell”.
Komentorivi avautuu. Aseta RemoteSigned-oikeus liittämällä alla oleva teksti komentoriville ja painamalla Enter. Lisätietoja oikeuksista on saatavilla Microsoftin verkkosivustolla.
Kun olet suorittanut skriptin, voit palauttaa oikeudet alla olevalla komennolla
Vaihe 3: Tallenna skripti tietokoneelle
Kopioi ja tallenna alla oleva komentosarja nimellä regmsgraph.ps1 tietokoneellesi. Ympäristönne kokoonpanosta riippuen skriptin joitakin yksityiskohtia saattaa olla tarpeen muokata.
#requires -Version 7.0
<#
End-to-end: Create Entra ID App Registration for app-only Microsoft Graph sendMail
AND scope it with an Exchange Online Application Access Policy using a mail-enabled security group.
Derived naming:
- SecretDisplayName is derived from AppDisplayName (unless overridden)
- GroupName and GroupAlias are derived from AppDisplayName (unless overridden)
Creates:
- App registration (Application)
- Enterprise app (Service Principal)
- Client secret (default 10 years)
- Grants Microsoft Graph application permission: Mail.Send (app role assignment)
- Mail-enabled security group (Distribution Group of Type Security)
- Application Access Policy restricting the app to members of that group
Change log:
2026-02-16 Initial version
#>
param(
# App registration name (source for derived names)
[Parameter(Mandatory = $false)]
[string]$AppDisplayName = "OpterMessageProxy",
# Secret settings
[Parameter(Mandatory = $false)]
[int]$SecretValidYears = 10,
# Optional overrides (if not provided, derived from AppDisplayName)
[Parameter(Mandatory = $false)]
[string]$SecretDisplayName,
[Parameter(Mandatory = $false)]
[string]$GroupName,
[Parameter(Mandatory = $false)]
[string]$GroupAlias,
# Optional: add initial members (UPN/email of mailboxes)
[Parameter(Mandatory = $false)]
[string[]]$InitialGroupMembers = @()
)
$ErrorActionPreference = "Stop"
function Ensure-Module {
param([Parameter(Mandatory = $true)][string]$Name)
if (-not (Get-Module -ListAvailable -Name $Name)) {
Install-Module $Name -Scope CurrentUser -Force
}
Import-Module $Name -ErrorAction Stop
}
function Normalize-Name {
<#
Creates a friendly base string from an app name for use in:
- distribution group display name
- distribution group alias (mailNickname)
Rules:
- keep letters/digits/spaces/hyphens
- collapse whitespace
- trim
#>
param([Parameter(Mandatory=$true)][string]$Name)
$n = $Name -replace '[^\p{L}\p{Nd}\s-]', ' ' # replace other chars with space
$n = $n -replace '\s+', ' ' # collapse spaces
$n = $n.Trim()
return $n
}
function To-Alias {
<#
Creates an Exchange-safe alias from a base name:
- lowercase
- letters/digits/hyphen only
- spaces -> hyphen
- collapse multiple hyphens
- trim hyphens
- max length 64 (Exchange alias limit is typically 64)
#>
param([Parameter(Mandatory=$true)][string]$Name)
$a = $Name.ToLowerInvariant()
$a = $a -replace '\s+', '-' # spaces to hyphen
$a = $a -replace '[^a-z0-9-]', '' # remove non-safe characters
$a = $a -replace '-{2,}', '-' # collapse hyphens
$a = $a.Trim('-')
if ($a.Length -gt 64) { $a = $a.Substring(0,64).Trim('-') }
if ([string]::IsNullOrWhiteSpace($a)) { throw "Could not derive a valid alias from AppDisplayName '$Name'." }
return $a
}
Write-Host "=== Installing/importing modules (may take several minutes, be patient) ==="
Ensure-Module -Name "Microsoft.Graph"
Ensure-Module -Name "ExchangeOnlineManagement"
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Applications
# ---- Derive names from AppDisplayName (unless overridden) ----
$baseName = Normalize-Name -Name $AppDisplayName
$derivedAliasBase = To-Alias -Name $baseName
if (-not $SecretDisplayName) {
$SecretDisplayName = "$derivedAliasBase-secret"
}
if (-not $GroupName) {
$GroupName = "$baseName - MailSend Allowed"
}
if (-not $GroupAlias) {
$GroupAlias = "$derivedAliasBase-mailsend-allowed"
if ($GroupAlias.Length -gt 64) { $GroupAlias = $GroupAlias.Substring(0,64).Trim('-') }
}
Write-Host ""
Write-Host "=== Derived/selected Names ==="
Write-Host "AppDisplayName : $AppDisplayName"
Write-Host "SecretDisplayName : $SecretDisplayName"
Write-Host "GroupName : $GroupName"
Write-Host "GroupAlias : $GroupAlias"
Write-Host ""
Write-Host "=== Connecting to Microsoft Graph ==="
$scopes = @(
"Application.ReadWrite.All",
"Application.Read.All",
"Directory.Read.All",
"AppRoleAssignment.ReadWrite.All"
)
Connect-MgGraph -Scopes $scopes | Out-Null
$ctx = Get-MgContext
Write-Host "Connected to Graph. TenantId: $($ctx.TenantId)"
Write-Host "`n=== Creating App Registration + Service Principal ==="
$app = New-MgApplication -DisplayName $AppDisplayName -SignInAudience "AzureADMyOrg"
$sp = New-MgServicePrincipal -AppId $app.AppId
Write-Host "App created:"
Write-Host " App (objectId) : $($app.Id)"
Write-Host " ClientId (appId) : $($app.AppId)"
Write-Host " SP (objectId) : $($sp.Id)"
Write-Host "`n=== Creating Client Secret (default $SecretValidYears years) ==="
$end = (Get-Date).ToUniversalTime().AddYears($SecretValidYears).ToString("o")
$pwdParams = @{
PasswordCredential = @{
DisplayName = $SecretDisplayName
EndDateTime = $end
}
}
$secret = Add-MgApplicationPassword -ApplicationId $app.Id -BodyParameter $pwdParams
Write-Host "Secret created (store the value now, it is shown only once)."
Write-Host " Secret expires (UTC): $end"
Write-Host "`n=== Granting Microsoft Graph Application Permission: Mail.Send ==="
$graphAppId = "00000003-0000-0000-c000-000000000000" # Microsoft Graph
$graphSp = Get-MgServicePrincipal -Filter "appId eq '$graphAppId'"
if (-not $graphSp) { throw "Microsoft Graph service principal not found in tenant." }
$mailSendRole = $graphSp.AppRoles | Where-Object {
$_.Value -eq "Mail.Send" -and $_.AllowedMemberTypes -contains "Application"
} | Select-Object -First 1
if (-not $mailSendRole) { throw "Could not find Microsoft Graph app role 'Mail.Send' (Application)." }
$assignBody = @{
principalId = $sp.Id
resourceId = $graphSp.Id
appRoleId = $mailSendRole.Id
}
New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId $sp.Id -BodyParameter $assignBody | Out-Null
Write-Host "Granted: Mail.Send (Application)"
Write-Host "`n=== Connecting to Exchange Online ==="
try {
Connect-ExchangeOnline -ErrorAction Stop | Out-Null
} catch {
Write-Warning "Connect-ExchangeOnline failed. Retrying with device code..."
Connect-ExchangeOnline -Device -ErrorAction Stop | Out-Null
}
Write-Host "`n=== Creating Mail-Enabled Security Group ==="
# Mail-enabled security group is created as a Distribution Group with -Type Security
$dg = New-DistributionGroup -Name $GroupName -Alias $GroupAlias -Type Security
Write-Host "Group created:"
Write-Host " Name : $($dg.DisplayName)"
Write-Host " Alias : $($dg.Alias)"
Write-Host " SMTP : $($dg.PrimarySmtpAddress)"
if ($InitialGroupMembers.Count -gt 0) {
Write-Host "`nAdding initial group members..."
foreach ($m in $InitialGroupMembers) {
Write-Host " + $m"
Add-DistributionGroupMember -Identity $dg.Identity -Member $m
}
} else {
Write-Host "`nNo initial members provided. Add allowed mailboxes to: $($dg.PrimarySmtpAddress)"
}
Write-Host "`n=== Creating Application Access Policy (RestrictAccess) ==="
New-ApplicationAccessPolicy `
-AppId $app.AppId `
-PolicyScopeGroupId $dg.PrimarySmtpAddress `
-AccessRight RestrictAccess `
-Description "Restrict app-only Graph mail access to members of $($dg.PrimarySmtpAddress)" | Out-Null
Write-Host "Application Access Policy created."
Write-Host "`n=== OUTPUT (save securely) ==="
Write-Host "Ms Graph Tenant Id : $($ctx.TenantId)"
Write-Host "Ms Graph Client Id : $($app.AppId)"
Write-Host "Ms Graph Client Secret : $($secret.SecretText)"
Write-Host "Secret Expires (UTC) : $end"
Write-Host "Scoped Group SMTP : $($dg.PrimarySmtpAddress)"
Write-Host ""
Write-Host "Test examples (EXO):"
Write-Host " Test-ApplicationAccessPolicy -AppId $($app.AppId) -Identity allowed.user@yourdomain.com"
Write-Host " Test-ApplicationAccessPolicy -AppId $($app.AppId) -Identity notallowed.user@yourdomain.com"
Write-Host ""
Write-Host "Reminder: app-only sending uses POST /users/{id|UPN}/sendMail (not /me/sendMail)."
Disconnect-ExchangeOnline -Confirm:$false | Out-Null
Disconnect-MgGraph | Out-Null
Mitä skripti tekee?
Jaamme sen lohkoihin.
-
Rivit 24–96 asettavat muuttujat, joita käytetään myöhemmin skriptissä, ja varmistavat, että muuttujien arvot toimivat.
-
Rivit 98–126 asentavat Azure-moduulit, joita tarvitaan REST-osan toimimiseen. Moduulit sijoitetaan polulle C:\Program Files\WindowsPowerShell\Modules\.
-
Rivit 128–137 kirjautuvat Microsoft Entra ID:hen (aiemmin Azure Active Directory) sovelluksen rekisteröinnin suorittamiseen tarvittavilla oikeuksilla.
-
Rivit 139–178 rekisteröivät Opterin Azure-sovellukseksi nimellä ”OpterMessageProxy” ja antavat sovellukselle oikeuden lähettää sähköpostia. Voit muuttaa nimen ”OpterMessageProxy” rivillä 27, mutta on helpompaa säilyttää oletusnimi, jos joudut ottamaan yhteyttä tukeen.
-
Rivit 180–214 luovat Exchangeen rajoitetuin oikeuksin varustetun oikeuksien ryhmän ja lisäävät siihen OpterMessageProxyn.
-
Rivit 216–230 näyttävät tiedot, jotka on syötettävä Opterin toimistoasetuksiin (välilehti Palvelimet).
Vaihe 4: Suorita skripti
Suorita komentosarja PowerShell 7.0:sta tai uudemmista versioista liittämällä tiedoston polku regmsgraph.ps1 komentoriville.
-
Jos haluat lisätä lähettäjän osoitteet manuaalisesti Exchangeen myöhemmin, suorita komentosarja rivin 1 mukaisesti. Korvaa ”C:\Temp” polulla, johon olet tallentanut skriptin.
-
Jos haluat lisätä lähettäjän osoitteet jo nyt, käytä riviä 2, kun suoritat komentosarjan, ja korvaa komentosarjan polku (”C:\Temp”) ja sähköpostiosoitteet oikeilla tiedoilla.
PS C:\Temp\regmsgraph.ps1
PS C:\Temp\regmsgraph.ps1 -InitialGroupMembers @("info@exempel.se","faktura@exempel.se")
Kun skripti suoritetaan, käytetään Azure-palveluun kirjautumistunnuksiasi. Varmista, että olet kirjautunut sisään tilillä, jolla on järjestelmänvalvojan oikeudet Microsoft Entra ID:lle ja Microsoft 365:lle organisaatiossasi. Jos et ole kirjautunut sisään, sinun on kirjauduttava sisään, kun skripti suoritetaan.
Sinulta kysytään, haluatko asentaa moduulit, ja sinun on vastattava kyllä.
Kun skripti on valmis, näytetään tiedot, jotka on lisättävä toimiston asetuksiin. Älä sulje PowerShell-konsolia ennen kuin olet tallentanut tiedot tai liittänyt ne tekstitiedostoon tai muualle, josta voit kopioida ne.
Asiakasluottamuksellisuutta ei voi hakea tai palauttaa. Jos et liitä sitä mihinkään, sinun on luotava uusi Azure-portaalissa. Muut tiedot voidaan tarvittaessa hakea Azure-portaalista jälkikäteen.
Vaihe 5: Yhdistä Opter ja Microsoft 365/MS Graph
Napsauta Asetukset > Toimistot > Palvelimet -välilehteä ja täytä seuraavat kentät PowerShell-konsolissa näkyvillä tiedoilla:
-
Ms Graph Tenant Id
-
Ms Graph Client Id
-
Ms Graph Client Secret
Tallenna asetukset ja napsauta sitten Testaa sähköposti. Määritä itsesi vastaanottajaksi ja tarkista, että saat viestin.
Jos kentässä Ms Graph Tenant Id on arvo, ei ole väliä, onko tämän välilehden yläpuolella olevat kentät täytetty (SMTP-palvelin, Portti, Käyttäjänimi, Salasana ja Suojattu lähetys (SSL)). Näitä tietoja ei käytetä, vaan todennus tapahtuu sovelluksen rekisteröinnin kautta Azuressa. Voi olla hyödyllistä poistaa niissä olevat tiedot, jotta väärinkäsityksiä ei pääse syntymään.
Sovelluksen rekisteröinti Azuressa
Löydät sovelluksen rekisteröinnin osoitteessa portal.azure.com etsimällä hakusanalla "optermessageproxy" ja valitsemalla hakutuloksen, joka on merkitty Application. Voit myös siirtyä sovellusten rekisteröintiin ja tarkastella rekisteröityjen ohjelmien luetteloa.
Kohdassa OpterMessageProxy voit katsoa ja kopioida Ms Graph Tenant Id = Directory (tenant) ID (2) ja Ms Graph Client Id = Application (client) ID (1).
Kohdetta Ms Graph Client Secret ei voi tarkastella tai palauttaa Azure-portaalissa. Jos et liittänyt sitä skriptin suorituksen aikana, sinun on luotava uusi salaisuus. Siirry vasemmanpuoleisessa valikossa kohtaan Manage (1) > Certificates & secrets (2) ja valitse New client secret. Sieltä voit myös tarkistaa, milloin asiakasluottamuksellisuus päättyy.
Useita verkkotunnuksia
Jos sinulla on useita verkkotunnuksia, esimerkiksi "transportfirman.centraleurope.se" ja "transportfirman.nordics.se", sinun on suoritettava komentosarja kerran jokaiselle verkkotunnukselle ja muutettava sovelluksen rekisteröinnin nimi joka kerta, kun suoritat sen. Ellei nimeä muuteta, edellinen sovelluksen rekisteröinti korvataan, kun komentosarja ajetaan uudelleen. Tee näin:
-
Muuta skriptin riviä 27 niin, että nimi tunnistaa ensimmäisen verkkotunnuksen. Kuljetusyrityksen tapauksessa rivi 27 muuttuu seuraavasti
[string]$AppDisplayName = "OpterMessageProxy",
osoitteeseen
[string]$AppDisplayName = "OpterMessageProxy-centraleurope",
-
Tallenna ja suorita skripti.
-
Muuta rivi 27 seuraavan verkkotunnuksen nimeksi. Kun kyseessä on Transport Company from
[string]$AppDisplayName = "OpterMessageProxy-centraleurope",
osoitteeseen
[string]$AppDisplayName = "OpterMessageProxy-nordics",
-
Tallenna ja suorita skripti uudelleen.
Nyt Azuressa on kaksi sovellusrekisteröintiä, joita voidaan hallita erikseen.
Vaihtoehtoiset lähettäjän osoitteet
Jos et lisännyt vaihtoehtoisia osoitteita skriptin käynnistyksen yhteydessä, voit tehdä sen Exchange-palvelimen OpterMessageProxy_group-turvallisuusryhmässä. Jos muutit nimeä rekisteröidessäsi Opterin Azureen, ryhmän nimi on määrittelemäsi + "_group". Kaikkien Opteriin lisäämiesi lähettäjäosoitteiden on oltava suojaryhmän jäseniä.
Lisätietoja ja esimerkkejä eri lähettäjäosoitteiden lisäämisestä on kohdassa Vaihtoehtoiset sähköpostiosoitteet.
Lähettäjäosoitteen lisääminen OpterMessageProxy_group-ryhmän jäseneksi Exchange-hallintakeskuksessa. Lisätietoja on saatavilla Microsoftin verkkosivustolla.