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.

  1. Azure Tenant ID

    Log ind på portal.azure.com og søg efter "klientorganisation" eller "tenant properties". Kopier derefter værdien for Tenant ID.

  2. Brugernavn for en administratorkonto til Microsoft 365

    Typisk en e-mailadresse. Da du er administrator, kan du sandsynligvis bruge din egen adresse.

  3. Microsoft 365-domæne

    Typisk det samme domæne som i e-mailadressen til administratorkontoen.

  4. 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.

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

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.

Se også