Senest opdateret: 2025-06-25
Send e-mails fra Opter med Microsoft 365
Gælder fra og med Opter 2025.06.00.
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 skriverettigheder til Azure AD og være Microsoft 365-administrator for din organisation – hvilket Opter ikke er. Scriptet foretager de nødvendige indstillinger i Azure og Exchange. Når scriptet er kørt, skal nogle oplysninger indtastes under fanen Servere i kontorindstillingerne.
Trin 1: Find dine Microsoft 365-oplysninger
Når scriptet kører, skal du angive følgende fire oplysninger. Start med at finde dem, så du har dem klar – f.eks. i en tekstfil, så du bare kan kopiere dem ind, når det bliver nødvendigt.
Du skal være administrator for Azure og Microsoft 365 i din organisation for at kunne finde oplysningerne og køre scriptet.
-
Azure Tenant ID
Log ind på portal.azure.com og søg efter "klientorganisation" eller "tenant properties". Kopier derefter værdien for Tenant ID.
-
Brugernavn for en administratorkonto til Microsoft 365
Typisk en e-mailadresse. Da du er administrator, kan du sandsynligvis bruge din egen adresse.
-
Microsoft 365-domæne
Typisk det samme domæne som i e-mailadressen til administratorkontoen.
-
E-mailadresse, der skal bruges som afsender
Dette er den adresse, der bruges til at sende e-mails fra Opter – altså den e-mailkonto, du har oprettet til Opter i Microsoft 365. Hvis du allerede har en eksisterende afsenderadresse, kan den findes i feltet Brugernavn under fanen Servere i kontorindstillingerne.
Trin 2: Åbn Windows Powershell
Søg efter "windows powershell" på Start-menuen i Windows, og åbn Windows PowerShell, ikke Windows PowerShell ISE.
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 rettighederne med kommandoen Set-ExecutionPolicy Restricted -Scope CurrentUser.
Trin 3: Kør scriptet
Kopier og gem nedenstående script som en PS1-fil på computeren. Kør det derefter fra Windows PowerShell ved at indsætte stien til filen i kommandolinjen og trykke på Enter.
Scriptet bruger specifikke versioner af visse komponenter. Det kan være nødvendigt at afinstallere komponenter, du allerede har installeret, først (hjælpekode findes i scriptet).
Fordi scriptet tvinger bestemte versioner ind, kan det "ødelægge" det eksisterende PowerShell-miljø, som derefter muligvis skal gendannes manuelt. Hvis du har et PowerShell-miljø, der anvendes i produktion og ikke bør ødelægges, bør du i stedet køre scriptet på en virtuel maskine.
#Run the following command manually in Windows PowerShell before running the script below: Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
#Script to create app registration in Azure with Mail.Send rights for e-mail addresses in Mail-Enabled secutity group created.
#Application secret is set to expire after 999 years. This can be changed to the desired value by modifying $AppYears value
#Please note that tenant wide admin consent must be granted manually after this script has been executed.
#For Opter AB, 2025-04-24, David Magnusson Rosén
#
#Change log
#------------------------------------------------------------------------------------------------------------------------------
#202
#
#
#Code to uninstall entire module with sub-modules if needed
#foreach ($module in (get-module -listavailable ModuleName*).name |get-unique) {write-host "removing module $module" uninstall-module $module }
#Install/import required modules
echo "Installing/importing required modules (can take several minutes)"
echo "Installing prerequisites..."
#PowerShellGet
if (Get-Module -ListAvailable -Name PowerShellGet)
{
echo "Updating module PowerShellGet..."
Update-Module -Name PowerShellGet -Force
}
else
{
echo "Installing module PowerShellGet..."
Install-Module -Name PowerShellGet -Scope CurrentUser -Force
}
echo "Installing module Az.Accounts..."
Install-Module -Name Az.Accounts -Scope CurrentUser -RequiredVersion 2.12.1 -AllowClobber -Repository PSGallery -Force
echo "Importing relevant functions from module Az.Accounts..."
Import-Module Az.Accounts -RequiredVersion 2.12.1
echo "Installing module Az.Resources..."
Install-Module -Name Az.Resources -Scope CurrentUser -RequiredVersion 6.6.0 -AllowClobber -Repository PSGallery -Force
echo "Importing relevant functions from module Az.Resources..."
Import-Module Az.Resources -RequiredVersion 6.6.0
echo "Installing module AzureAD..."
Install-Module AzureAD
echo "Importing relevant functions from module AzureAD..."
Import-Module AzureAD -Function Connect-AzureAD, Get-AzureADApplication, New-AzureADApplication, New-AzureADServicePrincipal, Add-AzADAppPermission, Get-AzADServicePrincipal, Get-AzADServicePrincipal_List
echo "Installing module Microsoft.Graph.Authentication..."
Install-Module Microsoft.Graph.Authentication -Scope CurrentUser -Repository PSGallery -AllowClobber -Force -requiredversion 1.27
echo "Importing relevant functions from module Microsoft.Graph.Authentication..."
Import-Module Microsoft.Graph.Authentication -Function Connect-MgGraph
echo ""
echo "Installing module Microsoft.Graph.Applications..."
Install-Module Microsoft.Graph.Applications -Scope CurrentUser -Repository PSGallery -AllowClobber -Force
echo "Importing relevant functions from module Microsoft.Graph.Applications..."
Import-Module Microsoft.Graph.Applications -Function Add-MgApplicationPassword
echo ""
echo "Installing module ExchangeOnlineManagement..."
Install-Module -Name ExchangeOnlineManagement -Scope CurrentUser -RequiredVersion 3.6.0 -Repository PSGallery -AllowClobber -Force
echo "Importing module ExchangeOnlineManagement..."
Import-Module ExchangeOnlineManagement -RequiredVersion 3.6.0 -Function Connect-ExchangeOnline, New-DistributionGroup, New-ApplicationAccessPolicy, Add-DistributionGroupMember
echo ""
echo "Necessary modules/functions installed/imported!"
echo ""
#Query for tenant Id
$TenantId = Read-Host "Please provide your Azure Tenant Id"
#Connect to AzureAD
Connect-AzureAD -TenantId $TenantId
Connect-AzAccount
#Create app registration and service principal
$appName = "OpterMessageProxy"
if(!($myApp = Get-AzureADApplication -Filter "DisplayName eq '$($appName)'" -ErrorAction SilentlyContinue))
{
$myApp = New-AzureADApplication -DisplayName $appName
$myServicePrincipal = New-AzureADServicePrincipal -AccountEnabled $true -AppId $myApp.AppId -AppRoleAssignmentRequired $true -DisplayName $myApp.DisplayName
$AppId = $myApp.AppId
}
#Wait for app registration to complete
echo "Wait for app registration to complete..."
Start-Sleep -Seconds 15
#Get service principal for Ms Graph
$graphApiId = '00000003-0000-0000-c000-000000000000'
$mailSendId = 'b633e1c5-b582-4048-a93e-9f11b44c7e96'
$graphSp = Get-AzADServicePrincipal -Filter "appId eq '$graphApiId'"
#Connect to MsGraph
Connect-MgGraph -Scopes "Application.ReadWrite.All", "DelegatedPermissionGrant.ReadWrite.All"
#Add Mail.Send rights to app registration
Add-AzADAppPermission -ObjectId $myApp.ObjectId -ApiId $graphApiId -PermissionId $mailSendId -Type Role
#Wait for rights assignment to complete
Start-Sleep -Seconds 15
#Create a secret for the app registration
$AppYears = "999"
$PasswordCred = @{
displayName = "Secret_${appName}_unlimited"
endDateTime = (Get-Date).AddYears($AppYears)
}
# Add App Client Secret - Valid for 999 years
$Secret = Add-MgApplicationPassword -ApplicationId $myApp.ObjectId -PasswordCredential $PasswordCred
$SecretText = $Secret.SecretText
# Write Client Secret value
echo "Secret: ${SecretText}"
#For future use
#Grant tenant-wide consent for app registration
# Get-MgServicePrincipal -Filter "displayName eq 'Microsoft Graph'" -Property AppRoles | Select -ExpandProperty appRoles |fl
# $params = @{
# "PrincipalId" ="aaaaaaaa-bbbb-cccc-1111-222222222222"
# "ResourceId" = "a0a0a0a0-bbbb-cccc-dddd-e1e1e1e1e1e1"
# "AppRoleId" = "df021288-bdef-4463-88db-98f22de89214"
# }
# New-MgServicePrincipalAppRoleAssignment -ServicePrincipalId 'aaaaaaaa-bbbb-cccc-1111-222222222222' -BodyParameter $params |
# Format-List Id, AppRoleId, CreatedDateTime, PrincipalDisplayName, PrincipalId, PrincipalType, ResourceDisplayName
#Connect to Exchange Online
$UserPrincipleName = Read-Host "Please provide your Microsoft365 admin user (usually yourname@yourdomain.com)"
Connect-ExchangeOnline -UserPrincipalName $UserPrincipleName
#Set up mail sending restrictions
$UserDomain = Read-Host "Please provide your Microsoft365 domain(usually yourdomain.com)"
$SenderAddress = Read-Host "Please provide an existing e-mail address to be used as sender"
$GroupName = "${appName}_group"
$mesGroup = New-DistributionGroup -Name $GroupName -PrimarySmtpAddress "${appName}@${UserDomain}" -Alias $GroupName.ToLower() -Type security
$accessPolicy = New-ApplicationAccessPolicy -AppId $myApp.AppId -PolicyScopeGroupId "${appName}@${UserDomain}" -AccessRight RestrictAccess -Description "Restrict this app to members of distribution group ${GroupName}."
$dgMember = Add-DistributionGroupMember -Identity $GroupName -Member $SenderAddress -Confirm:$false
#Show settings to use in Opter office settings and copy them to clipboard
#$ButtonType = [System.Windows.Forms.MessageBoxButtons]::OK
$MessageIcon = [System.Windows.Forms.MessageBoxIcon]::Information
$MessageBody = "Ms Graph Tenant Id: ${TenantId} `n"
$MessageBody += "Ms Graph Client Id: ${AppId} `n"
$MessageBody += "Ms Graph Client Secret: ${SecretText} `n"
$MessageInfo = "`n`n"
$MessageInfo += "NB!`nThe client secret disappears when you close this message and cannot be retreived or restored.`n"
$MessageInfo += "If you don't make a note of it, you have to create a new one manually in the Azure portal!`n`n"
$MessageInfo += "The above settings have been copied to the clipboard. Enter them in the office settings in Opter."
$MessageTitle = "Info to be used in Opter office settings"
Set-Clipboard -Value $MessageBody
#[System.Windows.Forms.MessageBox]::Show("${MessageBody} ${MessageInfo}",$MessageTitle,$ButtonType,$MessageIcon)
#Custom result form
$color = [System.Drawing.Color]::White
$form = New-Object System.Windows.Forms.Form
$form.Text = $MessageTitle
$form.BackColor = $color
$form.Width = 800
$form.Height = 275
$lblTenantId = New-Object System.Windows.Forms.Label
$lblTenantId.Text = "Ms Graph Tenant Id:"
$lblTenantId.AutoSize = $true
$lblTenantId.Font = New-Object System.Drawing.Font("Courier", 10)
$lblTenantId.Location = New-Object System.Drawing.Point(10,20)
$txtTenantId = New-Object System.Windows.Forms.TextBox
$txtTenantId.Height = 20
$txtTenantId.Width = 375
$txtTenantId.Multiline = $true
$txtTenantId.Text = $TenantId
$txtTenantId.Font = New-Object System.Drawing.Font("Courier New", 10)
$txtTenantId.Location = New-Object System.Drawing.Point(200,20)
$lblClientId = New-Object System.Windows.Forms.Label
$lblClientId.Text = "Ms Graph Client Id:"
$lblClientId.AutoSize = $true
$lblClientId.Font = New-Object System.Drawing.Font("Courier", 10)
$lblClientId.Location = New-Object System.Drawing.Point(10,50)
$txtClientId = New-Object System.Windows.Forms.TextBox
$txtClientId.Height = 20
$txtClientId.Width = 375
$txtClientId.Multiline = $true
$txtClientId.Text = $AppId
$txtClientId.Font = New-Object System.Drawing.Font("Courier New", 10)
$txtClientId.Location = New-Object System.Drawing.Point(200,50)
$lblClientSecret = New-Object System.Windows.Forms.Label
$lblClientSecret.Text = "Ms Graph Client Secret:"
$lblClientSecret.AutoSize = $true
$lblClientSecret.Font = New-Object System.Drawing.Font("Courier", 10)
$lblClientSecret.Location = New-Object System.Drawing.Point(10,80)
$txtClientSecret = New-Object System.Windows.Forms.TextBox
$txtClientSecret.Height = 20
$txtClientSecret.Width = 375
$txtClientSecret.Multiline = $true
$txtClientSecret.Text = $SecretText
$txtClientSecret.Font = New-Object System.Drawing.Font("Courier New", 10)
$txtClientSecret.Location = New-Object System.Drawing.Point(200,80)
$lblMessage = New-Object System.Windows.Forms.Label
$lblMessage.Text = $MessageInfo
$lblMessage.AutoSize = $true
$lblMessage.Font = New-Object System.Drawing.Font("Courier", 10)
$lblMessage.Location = New-Object System.Drawing.Point(10,90)
$form.Controls.Add($lblTenantId)
$form.Controls.Add($txtTenantId)
$form.Controls.Add($lblClientId)
$form.Controls.Add($txtClientId)
$form.Controls.Add($lblClientSecret)
$form.Controls.Add($txtClientSecret)
$form.Controls.Add($lblMessage)
$form.ShowDialog()
Du vil blive spurgt, om du vil installere modulerne – her skal du svare ja.
Når du bliver bedt om at indtaste de oplysninger, som du fandt frem til i trin 1 (f.eks. Azure tenant ID), skal du indsætte dem og trykke på Enter, hvorefter scriptet fortsætter.
Hvad gør scriptet?
Vi deler det op i blokke.
-
Linje 20-70 installerer MS Graph-modulerne til PowerShell. De er nødvendige for, at resten af manuskriptet fungerer. Modulerne installeres i C:\Program Files\WindowsPowerShell\Modules\.
-
Linje 72-77 logger på Azure AD.
-
Linje 80-119 registrerer Opter som en app i Azure med navnet "OpterMessageProxy" og giver denne app tilladelse til at sende e-mails. Du kan ændre navnet "OpterMessageProxy" i linje 81, men det er nemmere at beholde standardnavnet, hvis du får brug for at kontakte support.
-
Linje 132-142 tilføjer OpterMessageProxy til en tilladelsesgruppe i Exchange med begrænsede tilladelser.
-
Linje 144-224 viser de oplysninger, der skal indtastes i kontorindstillingerne i Opter (fanen Servere). Oplysningerne kopieres til udklipsholderen, men kan også kopieres fra den dialogboks, der åbnes. Luk ikke dialogboksen, før oplysningerne er blevet indtastet i kontorindstillingerne. Alternativt kan du indsætte dem i en tekstfil eller et andet sted, hvorfra du senere 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 4: Aktivér Azure-forbindelsen i Opter
Klik på Indstillinger > Kontor > Servere, og udfyld følgende felter med de oplysninger, du gemte i tekstfilen i trin 2:
-
Ms Graph Tenant ID
-
Ms Graph Client ID
-
Ms Graph Client Secret
Klik derefter på Test email, angiv dig selv som modtager, og tjek, 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 Sikke 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.
Trin 5: Giv appen OpterMessageProxy administratorrettigheder
Log ind på portal.azure.com, og søg efter "OpterMessageProxy". Gå til API permissions i menuen til venstre, og klik på Grant admin consent for {0}
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 kopiere den efter at have kørt scriptet, 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.
Alternative e-mailadresser
Hvis du f.eks. ønsker at sende fakturaer fra Opter med en anden adresse, f.eks. invoice@budfirman.se, skal du tilføje disse alternative adresser til 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". Læs mere på Microsofts hjemmeside: Tillad medlemmer at sende som eller på vegne af en gruppe (Microsoft). Alle afsenderadresser, du har tilføjet i Opter, skal være inkluderet i sikkerhedsgruppen.
Flere oplysninger og eksempler på, hvordan man tilføjer forskellige afsenderadresser, findes i Alternativa e-postadresser.
Det er ikke muligt at anvende tofaktorautentificering (2FA/MFA) på de e-mailkonti, der bruges af Opter.