Sist oppdatert: 2. mars 2026
Send e-post fra Opter med Microsoft 365
I denne artikkelen
Hvis du bruker Microsoft 365 som e-posttjeneste, må du autentisere Opter ved å registrere programmet som en app i Azure.
Appregistreringen i Azure kan gjøres med et PowerShell-skript som er tilgjengelig som kodeeksempel nedenfor. Grunnen til at skriptet ikke kan kjøres i forbindelse med en oppdatering, er at personen som kjører det, må ha tillatelse til å endre Microsoft Entra ID (tidligere Azure Active Directory) og være Microsoft 365-administrator for organisasjonen din, noe Opter ikke er. Skriptet gjør de nødvendige innstillingene i Entra ID og Exchange. Når skriptet er kjørt, må noen data legges inn i Servere-fanen i kontorinnstillingene.
Skriptet nedenfor må kanskje justeres for å fungere i ditt spesifikke miljø.
Trinn 1: Finn ut avsenderadresser
Finn ut hvilke e-postadresser du bruker til å sende e-post fra Opter. Du kan spesifisere hvilke e-postadresser du bruker når du kjører skriptet. Ellers må du gjøre dette manuelt i Exchange etterpå (se nedenfor).
-
Primær adresse: Tilgjengelig i feltet E-post på fanen Standard i kontorinnstillingene.
-
Adresse for regioner (hvis aktuelt): Tilgjengelig i felt E-post på fanen Standard for regionene.
-
Adresse for fakturaer og annen økonomisk kommunikasjon: Tilgjengelig i feltet E-post på fanen Fakturadetaljer i kontorinnstillingene, eller i regionene (hvis du bruker det).
Systemeieren av Opter vet hvilke avsenderadresser som brukes av Opter. Mer informasjon er tilgjengelig i Alternative e-postadresser.
Trinn 2: Åpne Powershell
Skriptet må kjøres i PowerShell 7 eller nyere, ikke Windows PowerShell ISE. Klikk på Start-menyen i Windows og søk etter «powershell».
En ledetekst åpnes. Angi RemoteSigned-rettigheten ved å lime inn det nedenstående i ledeteksten og trykke på Enter. Mer informasjon om rettighetene er tilgjengelig på Microsofts nettsted.
Når du har kjørt skriptet, kan du gjenopprette tillatelsene med følgende kommando
Trinn 3: Lagre skriptet på datamaskinen din
Kopier og lagre følgende skript som regmsgraph.ps1 på datamaskinen din. Avhengig av hvordan miljøet ditt er konfigurert, kan det være nødvendig å justere enkelte detaljer i skriptet.
#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
Hva gjør skriptet?
Vi deler det opp i blokker.
-
Linjene 24–96 angir variabler som brukes senere i skriptet og sikrer at verdiene for variablene fungerer.
-
Linjene 98–126 installerer Azure-modulene som trengs for at resten av skriptet skal fungere. Modulene legges i C:\Program Files\WindowsPowerShell\Modules\.
-
Linjene 128–137 logger inn på Microsoft Entra ID (tidligere Azure Active Directory) med de tillatelsene som kreves for å fullføre appregistreringen.
-
Linjene 139–178 registrerer Opter som en app i Azure med navnet «OpterMessageProxy» og gir appen tillatelse til å sende e-post. Du kan endre navnet «OpterMessageProxy» til noe annet på linje 27, men det er enklere å beholde standardnavnet hvis du av en eller annen grunn trenger å kontakte kundestøtte.
-
Linjene 180–214 oppretter en tillatelsesgruppe i Exchange med begrensede rettigheter og legger OpterMessageProxy til den.
-
Linjene 216–230 viser informasjonen som må legges inn i kontorinnstillingene i Opter (fanen Servere).
Trinn 4: Kjør skriptet
Kjør skriptet fra PowerShell 7.0 eller nyere ved å lime inn banen til filen regmsgraph.ps1 i kommandolinjen.
-
Hvis du senere ønsker å legge til avsenderadressene manuelt i Exchange, kjører du skriptet i henhold til linje 1 nedenfor. Erstatt «C:\Temp» med banen der du lagret skriptet.
-
Hvis du vil legge til avsenderadressene nå, bruk linje 2 når du kjører skriptet, og erstatt banen til skriptet («C:\Temp») og e-postadressene med de riktige.
PS C:\Temp\regmsgraph.ps1
PS C:\Temp\regmsgraph.ps1 -InitialGroupMembers @("info@exempel.se","faktura@exempel.se")
Når skriptet kjøres, bruker det autentiseringsopplysningene du er logget inn med på Azure. Sørg for at du er logget inn med en konto som har administratorrettigheter for Microsoft Entra ID og Microsoft 365 i organisasjonen din. Hvis du ikke er logget inn, må du logge inn når skriptet kjører.
Du blir spurt om du vil installere modulene, og du må svare ja på dette.
Når skriptet er klart, vises informasjonen som må legges inn i kontorinnstillingene. Ikke lukk PowerShell-konsollen før du har skrevet inn informasjonen eller limt den inn i en tekstfil eller et annet sted hvor du kan kopiere den fra.
Klienthemmeligheten kan ikke hentes tilbake eller gjenopprettes. Hvis du ikke limer den inn noe sted, må du opprette en ny i Azure-portalen. De andre dataene kan hentes fra Azure-portalen i etterkant hvis det er behov for det.
Trinn 5: Koble Opter med Microsoft 365/MS Graph
Klikk på Innstillinger > Kontor > fanen Servere og fyll ut følgende felt med informasjonen som vises i PowerShell-konsollen:
-
Ms Graph Tenant Id
-
Ms Graph Client Id
-
Ms Graph Client Secret
Lagre innstillingene og klikk deretter på Test e-post. Angi deg selv som mottaker og sjekk at du mottar en melding.
Hvis det finnes en verdi i Ms Graph Tenant Id-feltet, spiller det ingen rolle om feltene over på denne fanen er utfylt (SMTP-server, Port, Brukernavn, Passord og Sikker overføring (SSL)). Disse dataene brukes ikke, autentiseringen gjøres gjennom appregistreringen i Azure. Det kan være nyttig å fjerne informasjonen i dem slik at det ikke oppstår misforståelser.
App-registrering i Azure
Du finner appregistreringen på portal.azure.com ved å søke etter "optermessageproxy" og velge søkeresultatet merket Application. Du kan også gå til appregistreringer og se i listen over registrerte 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 gjenopprettes i Azure-portalen. Hvis du glemte å lime den inn da skriptet kjørte, må du opprette en ny hemmelighet. Gå til Manage (1) > Certificates & secrets (2) i menyen til venstre, og klikk på New client secret. Der kan du også sjekke når klienthemmeligheten utløper.
Flere domener
Hvis du har flere domener, for eksempel "transportfirman.centraleurope.se" og "transportfirman.nordics.se", må du kjøre skriptet én gang for hvert domene, og endre navnet på appregistreringen for hver gang du kjører det. Med mindre navnet endres, blir den forrige appregistreringen overskrevet når skriptet kjøres på nytt. Slik gjør du:
-
Endre linje 27 i skriptet slik at navnet identifiserer det første domenet. I tilfellet med Transport Company endres linje 27 fra
[string]$AppDisplayName = "OpterMessageProxy",
til
[string]$AppDisplayName = "OpterMessageProxy-centraleurope",
-
Lagre og kjør skriptet.
-
Endre linje 27 til navnet på neste domene. Når det gjelder transportselskap fra
[string]$AppDisplayName = "OpterMessageProxy-centraleurope",
til
[string]$AppDisplayName = "OpterMessageProxy-nordics",
-
Lagre og kjør skriptet på nytt.
Nå finnes det to appregistreringer i Azure som kan administreres hver for seg.
Alternative avsenderadresser
Hvis du ikke la til alternative adresser da du startet skriptet, kan du gjøre det i sikkerhetsgruppen OpterMessageProxy_group i Exchange. Hvis du endret navnet da du registrerte Opter i Azure, vil gruppen få det navnet du oppga + "_group". Alle avsenderadressene du har lagt til i Opter, må være inkludert som medlemmer av sikkerhetsgruppen.
Mer informasjon om og eksempler på hvordan du legger til forskjellige avsenderadresser, finnes på Alternative e-postadresser.
Slik legger du til en avsenderadresse som medlem av OpterMessageProxy_group i Exchange administrasjonssenter. Mer informasjon er tilgjengelig på Microsofts nettsted.