Senast uppdaterad: 2026-03-02
Skicka e-post från Opter med Microsoft 365
I den här artikeln
Om ni använder Microsoft 365 som e-posttjänst måste ni autentisera Opter genom att registrera programmet som en app i Azure.
Appregistreringen i Azure kan göras med ett PowerShell-skript som finns som kodexempel nedan. Anledningen till att skriptet inte kan köras i samband med en uppdatering är att den som kör det måste ha behörighet att ändra i Microsoft Entra ID (hette tidgare Azure Active Directory) och vara Microsoft 365-administratör för er organisation, vilket inte Opter är. Skriptet gör de inställningar som behövs i Entra ID och Exchange. När skriptet har körts behöver några uppgifter läggas in på fliken Servrar i kontorsinställningarna.
Skriptet som finns nedan är kan behöva justeras för att fungera i just er specifika miljö.
Steg 1: Ta reda på avsändaradresser
Ta reda på de e-postadresser som ni använder för att skicka e-post från Opter. Du kan ange vilka e-postadresser som ni använder redan när du kör skriptet. Annars måste du göra det manuellt i Exchange i efterhand (se Alternativa avsändaradresser nedan).
-
Primär adress: Finns i fältet E-post på fliken Allmänt i kontorsinställningarna.
-
Adress för regioner (om ni använder det): Finns i fältet E-post på fliken Allmänt på regionerna.
-
Adress för fakturor och andra ekonomimeddelanden: Finns i fältet E-post på fliken Fakturadetaljer i kontorsinställningarna, eller på regionerna (om ni använder det).
Systemägaren för Opter vet vilka avsändaradresser som används av Opter. Mer information finns i Alternativa e-postadresser.
Steg 2: Öppna Powershell
Skriptet måste köras i PowerShell 7 eller senare, inte Windows PowerShell ISE. Klicka på startmenyn i Windows och sök efter ”powershell”.
En kommandotolk öppnas. Sätt rättigheten RemoteSigned genom att klistra in nedanstående på kommandoraden och trycka på Enter. Mer information om rättigheterna finns på Microsofts webbplats.
När du har kört skriptet kan du ställa tillbaka rättigheterna med nedanstående kommando
Steg 3: Spara skriptet på datorn
Kopiera och spara nedanstående skript som regmsgraph.ps1 på datorn. Beroende på hur just er miljö är konfigurerad kan vissa detaljer i skriptet behöva justeras.
#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
Vad gör skriptet?
Vi bryter ner det i block.
-
Rad 24–96 sätter variabler som används senare i skriptet, och bäddar för att värdena för variablerna fungerar.
-
Rad 98–126 installerar de Azure-moduler som behövs för att resten av skriptet ska fungera. Modulerna läggs i C:\Program Files\WindowsPowerShell\Modules\.
-
Rad 128–137 loggar in på Microsoft Entra ID (tidigare Azure Active Directory) med den behörighet som behövs för att appregistreringen ska kunna genomföras.
-
Rad 139–178 registrerar Opter som app i Azure med namnet ”OpterMessageProxy” och ger den appen rättighet att skicka e-post. Du kan byta namnet ”OpterMessageProxy” till något annat på rad 27, men det är enklare att behålla standardnamnet om ni behöver kontakta supporten i något ärende.
-
Rad 180–214 skapar en behörighetsgrupp i Exchange med begränsade rättigheter och lägger in OpterMessageProxy i den.
-
Rad 216–230 visar den info som måste läggas in i kontorsinställningarna i Opter (fliken Servrar).
Steg 4: Kör skriptet
Kör skriptet från PowerShell 7.0 eller senare genom att klistra in sökvägen till filen regmsgraph.ps1 på kommandoraden.
-
Om du vill lägga till avsändaradresserna manuellt i Exchange senare kör du skriptet enligt rad 1 nedan. Ersätt ”C:\Temp” med sökvägen där du har sparat skriptet.
-
Om du vill lägga till avsändaradresserna redan nu använder du rad 2 när du kör skriptet och ersätter sökvägen till skriptet (”C:\Temp”) och e-postadresserna med de riktiga.
PS C:\Temp\regmsgraph.ps1
PS C:\Temp\regmsgraph.ps1 -InitialGroupMembers @("info@exempel.se","faktura@exempel.se")
När skriptet körs används de autentiseringsuppgifter som du är inloggad med på Azure. Se till att du är inloggad med ett konto som har administratörsbehörighet för Microsoft Entra ID och Microsoft 365 i er organisation. Om du inte är inloggad måste du logga in när skriptet körs.
Du kommer att få en fråga om du vill installera modulerna som du måste svara ja på.
När skriptet är klart visas info som behöver läggas in i kontorsinställningarna. Stäng inte PowerShell-konsolen innan du har lagt in informationen eller klistrat in den i en textfil, eller någon annanstans som du kan kopiera från.
Klienthemligheten går inte att hämta eller återställa. Om du inte klistrar in den någonstans måste du skapa en ny i Azure-portalen. De andra uppgifterna kan hämtas från Azure-portalen i efterhand om det skulle behövas.
Steg 5: Koppla ihop Opter med Microsoft 365/MS Graph
Klicka på Inställningar > Kontor > fliken Servrar och fyll i följande fält med den information som visas i PowerShell-konsolen:
-
Ms Graph Tenant Id
-
Ms Graph Client Id
-
Ms Graph Client Secret
Spara inställningarna och klicka sedan på Testa e-post. Ange dig själv som mottagare och kontrollera att du får ett meddelande.
Om det finns ett värde i fältet Ms Graph Tenant Id spelar det ingen roll om fälten ovanför på den här fliken är ifyllda (SMTP-server, Port, Användarnamn, Lösenord och Säker överföring (SSL)). De uppgifterna används inte, autentiseringen sker genom appregistreringen i Azure. Det kan vara bra att ta bort informationen i dem så att det inte sker några missförstånd.
Appregistreringen i Azure
Du hittar appregistreringen på portal.azure.com genom att söka på ”optermessageproxy” och välja det sökresultat som är märkt Program. Du kan också gå till appregistreringarna och leta i listan över registrerade program.
Under OpterMessageProxy kan du se och kopiera Ms Graph Tenant Id = Katalog-ID (klientorganisation) (2) och Ms Graph Client Id = Program-ID (klient) (1).
Ms Graph Client Secret kan inte visas eller återställas i Azure-portalen. Om du missade att klistra in det när skriptet kördes måste du skapa en ny hemlighet. Gå till Hantera (1) > Certifikat och hemligheter (2) i menyn till vänster och klicka på Ny klienthemlighet. Där kan du även kontrollera när klienthemligheten upphör att gälla.
Flera domäner
Om ni har flera domäner, till exempel ”transportfirman.centraleurope.se” och ”transportfirman.nordics.se”, måste ni köra skriptet en gång för varje domän, och ändra namnet på appregistreringen varje gång ni kör det. Om inte namnet ändras skrivs den föregående appregistreringen över när skriptet körs igen. Gör så här:
-
Ändra rad 27 i skriptet så att namnet identifierar den första domänen. I Transportfirmans fall ändras rad 27 från
[string]$AppDisplayName = "OpterMessageProxy",
till
[string]$AppDisplayName = "OpterMessageProxy-centraleurope",
-
Spara och kör skriptet.
-
Ändra rad 27 till namnet på nästa domän. I Transportfirmans fall från
[string]$AppDisplayName = "OpterMessageProxy-centraleurope",
till
[string]$AppDisplayName = "OpterMessageProxy-nordics",
-
Spara och kör skriptet igen.
Nu finns det två appregistreringar i Azure som kan hanteras separat.
Alternativa avsändaradresser
Om du inte lade till de alternativa adresserna när du startade skriptet kan du göra det i säkerhetsgruppen OpterMessageProxy_group i Exchange. Om ni ändrade namn när ni registrerade Opter i Azure heter gruppen det namn ni angav + ”_group”. Alla avsändaradresser ni har lagt till i Opter måste finnas med som medlemmar i säkerhetsgruppen.
Mer information och exempel på hur ni lägger till olika avsändaradresser finns i Alternativa e-postadresser.
Så här lägger du till en avsändaradress som medlem i gruppen OpterMessageProxy_group i Exchange admin center. Mer information finns på Microsofts webbplats.