Viimeisin päivitys: 2025-06-25

Lähetä sähköposteja Opterista Microsoft 365:n avulla

Sovelletaan alkaen Opter 2025.06.00:sta.

Jos käytät sähköpostipalveluna Microsoft 365:tä, sinun on todennettava Opter rekisteröimällä se sovelluksena Azuressa.

Sovelluksen rekisteröinti Azureen voidaan tehdä PowerShell-skriptillä, joka on saatavilla koodiesimerkkinä alla. Syy siihen, miksi skriptiä ei voi suorittaa päivityksen yhteydessä, on se, että skriptin suorittajalla on oltava Azure AD:n kirjoitusoikeudet ja hänen on oltava organisaatiosi Microsoft 365:n järjestelmänvalvoja, mikä Opter ei ole. Skripti tekee tarvittavat asetukset Azureen ja Exchangeen. Kun skripti on suoritettu, toimiston asetusten välilehdelle Palvelimet on syötettävä joitakin tietoja.

Vaihe 1: Selvitä Microsoft 365 -tietosi

Kun skripti käynnistyy, sinun on annettava seuraavat neljä tietoa. Aloita selvittämällä ne siten, että ne ovat saatavillasi, mieluiten tekstitiedostossa, jotta voit helposti kopioida ne, kun niitä tarvitaan.

Sinun on oltava Azuren ja Microsoft 365:n järjestelmänvalvoja organisaatiossasi, jotta voit käyttää tietoja ja suorittaa skriptin.

  1. Azure Tenant ID

    Kirjaudu osoitteeseen portal.azure.com ja etsi hakusanoilla "asiakasorganisaatio" tai "tenant properties". Kopioi sitten Tenant ID:n arvo.

  2. Microsoft 365 -järjestelmänvalvojan käyttäjätunnus

    Yleensä sähköpostiosoite. Koska olet järjestelmänvalvoja, voit luultavasti käyttää omaa osoitettasi.

  3. Microsoft 365 -verkkotunnus

    Yleensä sama verkkotunnus kuin järjestelmänvalvojatilin sähköpostiosoitteessa.

  4. Lähettäjänä käytettävä sähköpostiosoite

    Tämä on osoite, jota käytetään Opterista lähetettävien sähköpostiviestien lähettämiseen, eli sähköpostitili, jonka olet luonut Opteria varten Microsoft 365:ssä. Jos sinulla on jo olemassa oleva osoite, josta voit lähettää, se löytyy toimiston asetusten Palvelimet -välilehden Käyttäjänimi -kentästä.

Vaihe 2: Avaa Windows Powershell

Etsi Windowsin Käynnistä-valikosta "windows powershell" ja avaa Windows PowerShell, ei Windows PowerShell ISE.

Komentorivi avautuu. Aseta RemoteSigned-oikeus liittämällä alla oleva teksti komentoriville ja painamalla Enter. Lisätietoja oikeuksista on saatavilla Microsoftin verkkosivustolla.

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

Kun olet suorittanut skriptin, voit palauttaa oikeudet komennolla Set-ExecutionPolicy Restricted -Scope CurrentUser.

Vaihe 3: Suorita skripti

Kopioi ja tallenna seuraava skripti PS1-tiedostona tietokoneellesi. Suorita se sitten Windows PowerShellistä liittämällä polku komentoriville ja painamalla Enteriä.

Skripti käyttää tiettyjen komponenttien tiettyjä versioita. Sinun on mahdollisesti ensin poistettava jo asennetut komponentit (skriptissä on apukoodi).

Koska skripti pakottaa komponenttien tietyt versiot, se saattaa "häiritä" PowerShellin senhetkistä ympäristöä, ja se on palautettava manuaalisesti. Jos sinulla on PowerShell-ympäristö, jota käytetään tuotannossa ja jota ei saa häiritä, voit suorittaa skriptin virtuaalisella tietokoneella.

#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()

Sinulta kysytään, haluatko asentaa moduulit, ja sinun on vastattava kyllä.

Kun saat kehotuksen syöttää vaiheessa 1 selvittämiäsi tietoja, kuten Azure tenant ID:n, kopioi ja liitä ne ja paina Enteriä, jolloin skriptin suorittaminen jatkuu.

Mitä skripti tekee?

Jaamme sen lohkoihin.

  • Rivit 20-70 asentavat MS Graph -moduulit PowerShelliä varten. Niitä tarvitaan, jotta skriptin loppuosa toimii. Moduulit sijoitetaan polulle C:\Program Files\WindowsPowerShell\Modules\.

  • Rivit 72-77 kirjautuvat Azure AD:hen.

  • Rivit 80-119 rekisteröivät Opterin sovellukseksi Azuressa nimellä "OpterMessageProxy" ja antavat sovellukselle oikeuden lähettää sähköposteja. Voit muuttaa nimen "OpterMessageProxy" joksikin muuksi rivillä 81, mutta on helpompaa säilyttää oletusnimi, jos sinun on joskus otettava yhteys tukeen.

  • Rivit 132-142 lisäävät OpterMessageProxyn Exchange-käyttäjäoikeusryhmään, jolla on rajoitetut oikeudet.

  • Riveillä 144-224 näytetään tiedot, jotka on syötettävä Opterin toimistoasetuksiin (välilehti Palvelimet). Tiedot kopioidaan leikepöydälle, mutta ne voidaan kopioida myös avautuvasta valintaikkunasta. Älä sulje valintaikkunaa ennen kuin olet syöttänyt tiedot toimiston asetuksiin. Tai voit liittää tiedot tekstitiedostoon tai muuhun paikkaan, josta voit myöhemmin kopioida ne.

    Asiakasluottamuksellisuutta ei voi hakea tai palauttaa. Jos et liitä sitä mihinkään, sinun on luotava uusi Azure-portaalissa. Muut tiedot voidaan tarvittaessa hakea Azure-portaalista jälkikäteen.

Vaihe 4: Aktivoi Azure-yhteys Opterissa

Valitse Asetukset > Toimistot > Palvelimet -välilehti ja täytä seuraavat kentät tiedoilla, jotka liitit tekstitiedostoon vaiheessa 2:

  • Ms Graph Tenant ID

  • Ms Graph Client ID

  • Ms Graph Client Secret

Napsauta sitten kohtaa Testaa sähköposti, kirjoita itsesi vastaanottajaksi ja tarkista, että saat viestin.

Jos kentässä Ms Graph Tenant ID on arvo, ei ole väliä, onko tämän välilehden yläpuolella olevat kentät täytetty (SMTP-palvelin, Portti, Käyttäjänimi, Salasana ja Suojattu lähetys (SSL)). Näitä tietoja ei käytetä, vaan todennus tapahtuu sovelluksen rekisteröinnin kautta Azuressa. Voi olla hyödyllistä poistaa niissä olevat tiedot, jotta väärinkäsityksiä ei pääse syntymään.

Vaihe 5: Anna OpterMessageProxy-sovellukselle järjestelmänvalvojan oikeudet.

Kirjaudu sisään osoitteeseen portal.azure.com ja etsi "OpterMessageProxy". Siirry vasemmanpuoleisessa valikossa kohtaan API permissions ja napsauta kohtaa Grant admin consent for {0}

Sovelluksen rekisteröinti Azuressa

Löydät sovelluksen rekisteröinnin osoitteessa portal.azure.com etsimällä hakusanalla "optermessageproxy" ja valitsemalla hakutuloksen, joka on merkitty Application. Voit myös siirtyä sovellusten rekisteröintiin ja tarkastella rekisteröityjen ohjelmien luetteloa.

Kohdassa OpterMessageProxy voit katsoa ja kopioida Ms Graph Tenant ID = Directory (tenant) ID (2) ja Ms Graph Client ID = Application (client) ID (1).

Kohdetta Ms Graph Client Secret ei voi tarkastella tai palauttaa Azure-portaalissa. Jos et liittänyt sitä skriptin suorittamisen jälkeen, sinun on luotava uusi luottamuksellisuus. Siirry vasemmanpuoleisessa valikossa kohtaan Manage (1) > Certificates & secrets (2) ja valitse New client secret. Sieltä voit myös tarkistaa, milloin asiakasluottamuksellisuus päättyy.

Vaihtoehtoiset sähköpostiosoitteet

Jos esimerkiksi haluat lähettää laskut Opterista eri osoitteella, esimerkiksi osoitteella invoice@budfirman.se, lisää vaihtoehtoiset osoitteet OpterMessageProxy_group-suojausryhmään Exchangessa. Jos muutit nimeä rekisteröidessäsi Opterin Azureen, ryhmän nimi on määrittelemäsi + "_group". Lisätietoja on saatavilla Microsoftin verkkosivustolla: Salli jäsenten lähettää ryhmänä tai lähettää ryhmän puolesta (Microsoft). Kaikkien Opteriin lisäämiesi lähettäjäosoitteiden on oltava mukana suojausryhmässä.

Lisätietoja ja esimerkkejä eri lähettäjäosoitteiden lisäämisestä on kohdassa Alternativa e-postadresser.

Opterin käyttämillä sähköpostitileillä ei voi käyttää kaksitekijätodennusta (2FA, MFA).

Katso myös