Senest opdateret: 2. marts 2026
Send e-mails fra Opter med Microsoft 365
I denne artikel
Hvis du bruger Microsoft 365 som din e-mailtjeneste, skal du godkende Opter ved at registrere programmet som en app i Azure.
Appregistreringen i Azure kan udføres med et PowerShell-script, som findes som kodeeksempel nedenfor. Grunden til, at scriptet ikke kan køres i forbindelse med en opdatering, er, at den person, der kører det, skal have tilladelse til at ændre Microsoft Entra ID (tidligere Azure Active Directory) og være Microsoft 365-administrator for din organisation, hvilket Opter ikke er. Scriptet foretager de nødvendige indstillinger i Entra ID og Exchange. Når scriptet er kørt, skal nogle oplysninger indtastes under fanen Servere i kontorindstillingerne.
Nedenstående script skal muligvis tilpasses for at fungere i dit specifikke miljø.
Trin 1: Find afsenderadresser
Find ud af, hvilke e-mailadresser du bruger til at sende e-mails fra Opter. Du kan angive, hvilke e-mailadresser du bruger, når du kører scriptet. Ellers skal du gøre dette manuelt i Exchange bagefter (se nedenfor).
-
Primær adresse: Findes i feltet Email under fanen Generelt i kontorindstillingerne.
-
Adresse for regioner (hvis relevant): Tilgængelig i felt Email på fanen Generelt for regionerne.
-
Adresse til fakturaer og anden økonomisk korrespondance: Findes i feltet Email under fanen Fakturadetaljer i kontorindstillingerne eller i regionerne (hvis du bruger det).
Systemejeren af Opter ved, hvilke afsenderadresser der bruges af Opter. Du kan finde yderligere oplysninger i Alternative e-mailadresser.
Trin 2: Åbn Powershell
Scriptet skal køres i PowerShell 7 eller nyere, ikke Windows PowerShell ISE. Klik på Start-menuen i Windows og søg efter "powershell".
Et kommandovindue åbnes. Indstil rettigheden RemoteSigned ved at indsætte nedenstående kommando i kommandolinjen og trykke på Enter. Du kan finde flere oplysninger om rettighederne på Microsofts hjemmeside.
Når du har kørt scriptet, kan du gendanne tilladelserne med følgende kommando
Trin 3: Gem scriptet på din computer
Kopier og gem følgende script som regmsgraph.ps1 på din computer. Afhængigt af hvordan dit miljø er konfigureret, kan det være nødvendigt at justere nogle detaljer i scriptet.
#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
Hvad gør scriptet?
Vi deler det op i blokke.
-
Linjerne 24–96 indstiller variabler, der bruges senere i scriptet, og sikrer, at værdierne for variablerne fungerer.
-
Linjerne 98–126 installerer de Azure-moduler, der er nødvendige for, at resten af scriptet kan fungere. Modulerne installeres i C:\Program Files\WindowsPowerShell\Modules\.
-
Linjer 128–137 logger ind på Microsoft Entra ID (tidligere Azure Active Directory) med de tilladelser, der kræves for at gennemføre app-registreringen.
-
Linjerne 139–178 registrerer Opter som en app i Azure med navnet "OpterMessageProxy" og giver appen tilladelse til at sende e-mails. Du kan ændre navnet "OpterMessageProxy" til noget andet på linje 27, men det er nemmere at beholde standardnavnet, hvis du af en eller anden grund har brug for at kontakte support.
-
Linjerne 180–214 opretter en tilladelsesgruppe i Exchange med begrænsede rettigheder og tilføjer OpterMessageProxy til den.
-
Linjerne 216–230 viser de oplysninger, der skal indtastes i kontorindstillingerne i Opter (fanen Servere).
Trin 4: Kør scriptet
Kør scriptet fra PowerShell 7.0 eller nyere ved at indsætte stien til filen regmsgraph.ps1 i kommandolinjen.
-
Hvis du senere vil tilføje afsenderadresserne manuelt i Exchange, skal du køre scriptet i henhold til linje 1 nedenfor. Erstat "C:\Temp" med den sti, hvor du har gemt scriptet.
-
Hvis du vil tilføje afsenderadresserne nu, skal du bruge linje 2, når du kører scriptet, og erstatte stien til scriptet ("C:\Temp") og e-mailadresserne med de korrekte.
PS C:\Temp\regmsgraph.ps1
PS C:\Temp\regmsgraph.ps1 -InitialGroupMembers @("info@exempel.se","faktura@exempel.se")
Når scriptet kører, bruger det de godkendelsesoplysninger, du er logget ind med på Azure. Sørg for, at du er logget ind med en konto, der har administratorrettigheder til Microsoft Entra ID og Microsoft 365 i din organisation. Hvis du ikke er logget ind, skal du logge ind, når scriptet kører.
Du vil blive spurgt, om du vil installere modulerne – her skal du svare ja.
Når scriptet er klar, vises de oplysninger, der skal indtastes i kontorindstillingerne. Luk ikke PowerShell-konsollen, før du har indtastet oplysningerne eller indsat dem i en tekstfil eller et andet sted, hvorfra du kan kopiere dem.
Klienthemmeligheden kan ikke hentes eller gendannes. Hvis du ikke har gemt den et sted, skal du oprette en ny i Azure-portalen. De øvrige oplysninger kan hentes fra Azure-portalen bagefter, hvis det bliver nødvendigt.
Trin 5: Forbind Opter med Microsoft 365/MS Graph
Klik på Indstillinger > Kontor > fanen Servere og udfyld følgende felter med de oplysninger, der vises i PowerShell-konsollen:
-
Ms Graph Tenant Id
-
Ms Graph Client Id
-
Ms Graph Client Secret
Gem indstillingerne, og klik derefter på Test email. Indtast dig selv som modtager og kontroller, at du modtager en besked.
Hvis der findes en værdi i feltet Ms Graph Tenant Id, er det ligegyldigt, om felterne ovenfor under denne fane er udfyldt (SMTP-server, Port, Brugernavn, Adgangskode og Sikker forbindelse (SSL)). Disse oplysninger bruges ikke, da autentificeringen sker via appregistreringen i Azure. Det kan være en god idé at fjerne oplysningerne i dem for at undgå misforståelser.
Appregistrering i Azure
Du kan finde appregistreringen på portal.azure.com ved at søge på "optermessageproxy" og vælge det søgeresultat, der hedder Application. Du kan også gå til appregistreringer og lede i listen over registrerede programmer.
Under OpterMessageProxy kan du se og kopiere Ms Graph Tenant Id = Directory (tenant) ID (2) og Ms Graph Client Id = Application (client) ID (1).
Ms Graph Client Secret kan ikke vises eller gendannes i Azure-portalen. Hvis du glemte at indsætte den, da scriptet kørte, skal du oprette en ny hemmelighed. Gå til Manage (1) > Certificates & secrets (2) i menuen til venstre, og klik på New client secret. Der kan du også tjekke, hvornår klienthemmeligheden udløber.
Flere domæner
Hvis du har flere domæner, f.eks. "transportfirman.centraleurope.se" og "transportfirman.nordics.se", skal du køre scriptet én gang for hvert domæne og ændre navnet på app-registreringen, hver gang du kører det. Medmindre navnet ændres, overskrives den tidligere app-registrering, når scriptet køres igen. Sådan gør du:
-
Ændr linje 27 i scriptet, så navnet identificerer det første domæne. I tilfælde af transportvirksomheden ændres linje 27 fra
[string]$AppDisplayName = "OpterMessageProxy",
til
[string]$AppDisplayName = "OpterMessageProxy-centraleurope",
-
Gem og kør scriptet.
-
Ændr linje 27 til navnet på det næste domæne. I tilfælde af transportvirksomhed fra
[string]$AppDisplayName = "OpterMessageProxy-centraleurope",
til
[string]$AppDisplayName = "OpterMessageProxy-nordics",
-
Gem og kør scriptet igen.
Nu er der to app-registreringer i Azure, som kan administreres hver for sig.
Alternative afsenderadresser
Hvis du ikke tilføjede de alternative adresser, da du startede scriptet, kan du gøre det i sikkerhedsgruppen OpterMessageProxy_group i Exchange. Hvis du ændrede navnet under registreringen af Opter i Azure, vil gruppen få det navn, du angav, efterfulgt af "_group". Alle de afsenderadresser, du har tilføjet til Opter, skal være inkluderet som medlemmer af sikkerhedsgruppen.
Flere oplysninger og eksempler på, hvordan man tilføjer forskellige afsenderadresser, findes i Alternative e-mailadresser.
Sådan tilføjer du en afsenderadresse som medlem af OpterMessageProxy_group i Exchange admin center. Du kan finde flere oplysninger på Microsofts hjemmeside.