ModernMailTools.psm1

# $global:

function Register-ModernMailMessageEntraIDApp {
    <#
    .SYNOPSIS
        Registers an Entra ID App.
    .DESCRIPTION
        Registers an app in Entra ID, assigning necessary permissions and outputting relevant information.
    .PARAMETER ApplicationName
        The name of the application to register.
    .EXAMPLE
        Register-ModernMailMessageEntraIDApp -ApplicationName "M365 ModernMailTools"
    .INPUTS
        None
    .OUTPUTS
    .NOTES
    #>

    param (
        [Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [string]$ApplicationName
        #[string]$Tenant,
        #[string]$TenantId,
        #[string]$TenantName
    )

    if (-not $DisableTelemetry) {
        Write-Telemetry -EventName "RegisterModernMailMessageEntraIDApp"
    }

    # Reference:
    # https://pnp.github.io/powershell/cmdlets/Register-PnPAzureADApp.html

    #Import-Module Microsoft.Graph.Authentication
    #Import-Module Microsoft.Entra.Authentication

    #$ApplicationName = "Test M365 ModernMailTools"
    ##$ApplicationName = "Test PS ModernMailTools"
    ##$ApplicationName = "Test M365 SendMail"
    ##$ApplicationName = "Test PS SendMail"

    #Connect-MgGraph
    if (-not (Get-EntraContext)) {
        Connect-Entra -Scopes 'Application.ReadWrite.All' -NoWelcome
        #Connect-Entra -Scopes 'Application.ReadWrite.All' -NoWelcome #-TenantId
    }


    #$application = Get-EntraApplication -Filter "DisplayName eq 'My new application'"
    $application = Get-EntraApplication -Filter "DisplayName eq '$ApplicationName'"
    Write-Verbose "VAR: $($application.DisplayName)" -Verbose

    if(!$application) {
        #$application = New-EntraApplication -DisplayName 'My new application'
        $application = New-EntraApplication -DisplayName $ApplicationName
                    #New-EntraServicePrincipal -AppId $myApp.AppId -DisplayName 'My new service principal'
        Write-Verbose "APP: $($application.DisplayName)" -Verbose
    }

    $requiredResourceAccess = @(
        @{resourceAppId    = '00000003-0000-0000-c000-000000000000' # Microsoft Graph
            resourceAccess = @(
                #@{
                # id = 'c79f8feb-a9db-4090-85f9-90d820caa0eb' # Application.Read.All (Delegate) - Read applications
                # type = 'Scope'
                #}
                #@{
                # id = '9a5d68dd-52b0-4cc2-bd40-abcf44ac3a30' # Application.Read.All (Application) - Read all applications
                # type = 'Role'
                #}
                @{
                    id   = 'e383f46e-2787-4529-855e-0e479a3ffac0' # Mail.Send (Delegate) - Send mail as a user
                    type = 'Scope'
                    # Role - AADSTS650051: Claim is invalid: Mail.Send does not exist in client application's RequiredResourceAccess.
                }
                #@{
                # id = 'a367ab51-6b49-43bf-a716-a1fb06d2a174' # Mail.Send.Shared (Delegate) - Send mail on behalf of others
                # type = 'Scope'
                #}
                @{
                    id   = 'b633e1c5-b582-4048-a93e-9f11b44c7e96' # Mail.Send (Application) - Send mail as any user
                    type = 'Role'
                }
                @{
                    id   = '258f6531-6087-4cc4-bb90-092c5fb3ed3f' # SMTP.Send (Delegate) - Send emails from mailboxes using SMTP AUTH
                    type = 'Scope'
                    # Role - AADSTS650051: Claim is invalid: SMTP.Send does not exist on resource application 00000003-0000-0000-c000-000000000000.
                }
                )
        }
        @{resourceAppId    = '00000002-0000-0ff1-ce00-000000000000' # Office 365 Exchange Online
            resourceAccess = @(
                @{
                    id   = 'b633e1c5-b582-4048-a93e-9f11b44c7e96' # Mail.Send (Application) - Send mail as any user
                    type = 'Role'
                }
            )
        }
        )

    $applicationEdited = Set-EntraApplication -ApplicationId $application.Id -RequiredResourceAccess $requiredResourceAccess
    # AADSTS500113: No reply address is registered for the application.

    #Set-EntraApplication -ApplicationId $application.Id -ReplyUrls "" # N/A
    # https://login.microsoftonline.com/common/oauth2/nativeclient + http://localhost
    # Ensure you have a 'Mobile and desktop applications' platform with redirect to 'http://localhost' configured (and not a 'Web' Platform).

    # Grant-EntraAdminConsent -AppId "your-application-id" # N/A
    # https://login.microsoftonline.com/{organization}/adminconsent?client_id={client-id}

    if($applicationEdited){
        $context = Get-EntraContext
        $clientId = $application.AppId
        $tenantId = $context.TenantId
        $consentUrl = "https://login.microsoftonline.com/$tenantId/adminconsent?client_id=$clientId"

        #Write-host -ForegroundColor Gray "Opening: $consentUrl"
        Write-Output "Opening: $consentUrl"
        #Write-Information "Opening: $consentUrl"
        #Write-Verbose "Opening: $consentUrl"
        Start-Process $consentUrl
    }
    Write-Verbose "EDIT: $($application.DisplayName)" -Verbose
}


function Send-ModernMailMessage {
    <#
    .SYNOPSIS
        Sends an email message.
    .DESCRIPTION
        The Send-ModernMailMessage cmdlet sends an email message from within PowerShell.
    .EXAMPLE
        Send-ModernMailMessage -From "user01@fabrikam.com" -To "user02@fabrikam.com" -Subject "Test mail"
        Send-ModernMailMessage -From "user01@fabrikam.com" -To "user02@fabrikam.com" -Subject "Test mail" -SmtpServer smtp.contoso.com -UseSsl -Port 587
    .INPUTS
        None
    .OUTPUTS
    .NOTES
        Use "Enable-MailMessageAlias" to enable the command "Send-MailMessage".
    #>

    param (
        [Parameter(Position = 0)]
        # The path and file names of files to be attached to the email message.
        [alias("Attachments")]
        [String[]]$Attachment,

        [Parameter(Position = 1)]
        # Email addresses that receive a copy of the mail but are not listed as recipients of the message.
        #[Array] $Bcc,
        [String[]]$Bcc,

        [Parameter(Position = 2)]
        # The body (content) of the email message.
        [alias("Message")]
        #[string[]] $Text,
        [String]$Body,

        [Parameter(Position = 3)]
        # Indicates that the value of the Body parameter contains HTML.
        #[alias("Body")]
        #[string[]] $HTML,
        [Switch]$BodyAsHtml,

        [Parameter(Position = 4)]
        # The encoding used for the body and subject.
        # Explicitly reference System.Text.Encoding
        [System.Text.Encoding]$Encoding = [System.Text.Encoding]::Default,

        [Parameter(Position = 5)]
        # Email addresses to which a carbon copy (CC) of the email message is sent.
        #[Array] $Cc,
        [String[]]$Cc,

        [Parameter(Position = 6)]
        # Delivery notifications (if accepted by the recipient)
        [alias("Dno")]
        #[System.Net.Mail.DeliveryNotificationOptions]$DeliveryNotificationOption,
        # Explicitly reference System.Net.Mail
        [ValidateSet('None', 'OnSuccess', 'OnFailure', 'Delay', 'Never')]
        # Delivery notification options with validation
        [String[]]$DeliveryNotificationOption,

        [Parameter(Position = 7, Mandatory = $true)]
        # The address from which the mail is sent.
        #[Parameter(Mandatory = $true)]
        #[object] $From,
        [alias("UserId")]
        [ValidateNotNullOrEmpty()]
        [String]$From,

        [Parameter(Position = 8)]
        # Deprecated??
        [alias('Host')]
        [alias('Server')]
        [String]$SmtpServer = "smtp.office365.com",

        [Parameter(Position = 9)]
        # The priority of the email message.
        #[System.Net.Mail.MailPriority]$Priority, # Explicitly reference System.Net.Mail.MailPriority
        [alias('Importance')]
        [ValidateSet('Low', 'Normal', 'High')]
        [string] $Priority,

        [Parameter(Position = 10)]
        # Specifies additional email addresses (other than the From address) to use to reply to this message
        #[string] $ReplyTo,
        [String[]]$ReplyTo,

        [Parameter(Position = 11)]
        # The subject of the email message.
        #[string] $Subject,
        [String]$Subject,

        [Parameter(Position = 12, Mandatory = $true)]
        # The addresses to which the mail is sent
        #[Array] $To,
        #[Parameter(Mandatory = $true)]
        [ValidateNotNullOrEmpty()]
        [String[]]$To,

        [Parameter(Position = 13)]
        # Deprecated?
        [PSCredential]$Credential,

        [Parameter(Position = 14)]
        # Deprecated?
        #[Bool]$UseSsl = $true,
        [Switch]$UseSsl,

        [Parameter(Position = 15, Mandatory = $false)]
        # Deprecated?
        #[Parameter(Position = 15)]
        #[Parameter(Mandatory = $false)]
        [Int32]$Port = 587,

        # Indicates whether to save the message in Sent Items.
        [Switch]$SaveToSentItems,

        # Indicates whether a read receipt is requested for the message.
        #ToDevelop:IsReadReceiptRequested
        [Switch]$RequestReadReceipt,

        # Indicates whether a delivery receipt is requested for the message.
        #ToDevelop: IsDeliveryReceiptRequested
        [Switch]$RequestDeliveryReceipt,

        #ToDevelop: Message
        #ToDevelop: BodyParameter

        #-DisableTelemetry
        #-DisableTelemetry $false
        #[Parameter(Mandatory = $false, HelpMessage = 'Disable telemetry')]
        #[bool]$DisableTelemetry,

        # Disable Telemetry
        # If set, telemetry information will not be logged.
        [Parameter(Mandatory = $false, HelpMessage = 'Disable telemetry')]
        [switch] $DisableTelemetry,

        # Modus defines the mode of operation for sending notifications.
        # Default: None
        # Fallback: Graph with Delegation (user-based interaction).
        # Fallback: User-based delegation for Microsoft Graph (interactive).
        # Recommended:
        # - 'GRAPH': App-only authentication (certificate-based) for Graph API.
        # - 'SMTP': SMTP-based email sending (e.g., OAuth2 authentication).
        # - 'TEAMS': Teams webhook notification (send notifications to a Teams channel).
        [ValidateSet('GRAPH', 'SMTP', 'TEAMS')]
        [String]$Modus = 'GRAPH',

        # Specifies the application ID of the service principal that is used in application-based authentication.
        [alias('$ApplicationId')]
        [string]$ClientId,

        # Specifies the ID of a tenant.
        [string]$TenantId,

        # Specifies the certificate thumbprint of a digital public key X.509 certificate of an application that has permission to perform this action.
        [string]$CertificateThumbprint

    )
    <#
    Reference:
        https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/send-mailmessage?view=powershell-7.5
        https://ss64.com/ps/send-mailmessage.html
        https://learn.microsoft.com/en-us/powershell/module/microsoft.graph.users.actions/send-mgusermail?view=graph-powershell-1.0
 
        Send-MailMessage -From "User01 <user01@fabrikam.com>"" -To "User02 <user02@fabrikam.com>" -Subject "Test mail"
        Send-MailMessage -To "User01 <user01@contoso.com>" -From "User02 <user02@contoso.com>" -Subject "Test mail" -SmtpServer smtp.contoso.com -UseSsl -Port 587
    #>


    ## Defensive handling for Encoding parameter
    #if ($null -eq $Encoding) {
    # $Encoding = [System.Text.Encoding]::Default
    #} elseif ($Encoding -is [string]) {
    # $Encoding = [System.Text.Encoding]::GetEncoding($Encoding)
    #}

    if (-not $From) { throw "Parameter 'From' is required." }
    if (-not $To)   { throw "Parameter 'To' is required." }

    # Deprecated values
    if ($SmtpServer) { Write-Verbose "Deprecated: $($SmtpServer)" }
    if ($Credential) { Write-Verbose "Deprecated: $($Credential)" }
    if ($UseSsl) { Write-Verbose "Deprecated: $($UseSsl)" }
    if ($Port) { Write-Verbose "Deprecated: $($Port)" }

    # Development values
    #if ($Attachments) { Write-Verbose "Development: $($Attachments)" }
    if ($Cc) { Write-Verbose "Development: $($Cc)" }
    if ($Bcc) { Write-Verbose "Development: $($Bcc)" }
    if ($DeliveryNotificationOption) { Write-Verbose "Development: $($DeliveryNotificationOption)" } # DNO
    if ($Priority) { Write-Verbose "Development: $($Priority)" }
    if ($ReplyTo) { Write-Verbose "Development: $($ReplyTo)" }
    if ($SaveToSentItems) { Write-Verbose "Development: $($SaveToSentItems)" }
    if ($RequestReadReceipt) { Write-Verbose "Development: $($RequestReadReceipt)" } # DNO
    if ($RequestDeliveryReceipt) { Write-Verbose "Development: $($RequestDeliveryReceipt)" } # DNO
    if ($Encoding) { Write-Verbose "Development: $($Encoding)" }


    if (-not $DisableTelemetry) {
        Write-Telemetry -EventName "SendModernMailMessage"
    }

    # -- Authentication
    #Get-MgContext
    #Get-EntraContext



    switch ($Modus) {
        'GRAPH' {
            # Graph - Application
            # Implement Microsoft Graph API logic using certificate for authentication (app-based)
            Write-Debug "Sending email via Microsoft Graph Application (certificate-based) to $Recipient"
            # Implement Microsoft Graph API logic using certificate-based authentication (app-only)
            Write-Debug "Sending email via Microsoft Graph Application (app-only authentication) to $Recipient"

            if ($ClientId -and $TenantId -and $CertificateThumbprint) {
                Connect-MgGraph `
                    -ClientId $ClientId `
                    -TenantId $TenantId `
                    -CertificateThumbprint $CertificateThumbprint
            }

            #try {
            # $user = Get-MgUser -UserId $From -ErrorAction Stop
            #} catch {
            # throw "The user specified in -From ('$From') does not exist in Microsoft 365."
            #}
        }
        'SMTP' {
            # Implement SMTP with OAuth2 authentication here
            # Write-Debug "Sending email via SMTP to $Recipient"
            # Implement SMTP with OAuth2 authentication here
            # Write-Debug "Sending email via SMTP to $Recipient"


            # SMTP
            Import-Module EntraAuth


            ## During the Connectiong
            #$clientId = $application.AppId
            #$tenantId = $context.TenantId
            #$token = Connect-EntraService -ClientID $clientId -TenantID $tenantId -Service GraphBeta -PassThru
            #$token.Scopes

            Connect-EntraService -ClientID Graph -Scopes "SMTP.Send" -Service GraphBeta
            #Get-EntraService

            # After already being connected
            $token = Get-EntraToken -Service GraphBeta
            #$token.Scopes # SMTP.Send

            #$token | fl *
            #$xauth2 = $token.AccessToken
            #$secure_xauth2 = ConvertTo-SecureString -AsPlainText $xauth2 -Force # Token
            #$secure_xauth2 = ConvertTo-SecureString -AsPlainText "[Password]" -Force # Pw (with Enabled MFA)
            ##[pscredential]$credential = New-Object System.Management.Automation.PSCredential("AutomateB@contoso.onmicrosoft.com", $secure_xauth2)


        }
        'TEAMS' {
            # Implement Teams webhook notification logic here
            Write-Debug "Sending Teams notification to $Recipient"

            Connect-MicrosoftTeams`
                -CertificateThumbprint $CertificateThumbprint `
                -ApplicationId $ClientId `
                -TenantId $TenantId
        }
        default {
            # Handle invalid modus, if necessary
            Write-Debug "Invalid modus specified: $Modus"
            # You can also add additional handling for invalid modus, like logging or exit

            # Graph - Delegated (Fallback)
            # Implement Microsoft Graph API logic using delegated user consent (interactive)
            Write-Debug "Sending email via Microsoft Graph Delegation (user-based) to $Recipient"
            # Implement Microsoft Graph API logic using delegated user consent (interactive)
            Write-Debug "Sending email via Microsoft Graph Delegation (user-based authentication) to $Recipient"

            # Only connect if not already connected
            if (-not (Get-MgContext)) {
                Connect-MgGraph -Scopes "Mail.Send" -NoWelcome
            }
            $IsDelegated = $true
        }
    }


    # -- Settings

    $From = if ($IsDelegated) {(Get-MgContext).Account} else {$From}
    #$From = if ($Modus -eq 'GRAPH_DELEGATION') {(Get-MgContext).Account} else {$From}

    #$To = if ($To.Count -gt 1) {} else { $To[0] } # Handle Array

    $MessageBody = @{
        contentType = if ($BodyAsHtml) { "HTML" } else { "Text" }
        #content = if ($Body) { $Body -join [System.Environment]::NewLine } else { "" }
        content = if ($Body) { $Body -join [System.Environment]::NewLine } else { "This email is sent via Microsoft Graph." }
    }
    if (!$Subject) { $Subject  = "Test message from ModernMailTools (Modus: $Modus)" }


    if ($Attachment){
        try {
            #$Attachment = "..\_readme.md"
            #Test-Path $Attachment # True
            #(Get-Item -Path $Attachment).Length -lt 3000000 # 3191 | True
            if ((Test-Path $Attachment) -and ((Get-Item -Path $Attachment).Length -lt 3000000)) {
                # Attachments are under 4MB or empty

                #Get File Name and Base64 string
                $FileName = (Get-Item -Path $Attachment).Name
                $FileBytes = [Convert]::ToBase64String([IO.File]::ReadAllBytes($Attachment))
                Write-Verbose "Name: $($FileName)"
                Write-Verbose "Length: $($FileBytes.Length)"
            } else {
                <#Do this if attachments are over 4MB#>
            }
        }    catch {
            Write-Verbose $_
            #Write-Error $_.Exception.Message
        }
    }

    # -- Send
    if ($From) { Write-Verbose "Send v1: $($From)"}
    if ($MessageBody) { Write-Verbose "Send v1: $($MessageBody | Out-String)"}
    if ($Subject) { Write-Verbose "Send v1: $($Subject)"}
    if ($To) { Write-Verbose "Send v1: $($To)"}

    Write-Debug "Modus: $($Modus)" #-Debug
    #If ($null -eq $Modus){$Modus = 'GRAPH'}
    switch ($Modus) {
        'GRAPH' {
            # Graph

            $params = [ordered] @{
                # https://docs.microsoft.com/en-us/graph/api/resources/message?view=graph-rest-1.0
                message         = [ordered] @{
                    subject                    = $Subject
                    body                       = $MessageBody
                    #from = $From
                    toRecipients               = @(
                        @{
                            emailAddress = @{
                                address = $To[0]
                            }
                        }
                    )
                    #toRecipients = @(
                    # @{
                    # emailAddress = @{
                    # address = "meganb@contoso.com"
                    # }
                    # }
                    #)
                    #ccRecipients = @()
                    #bccRecipients = @()
                    #replyTo = @()
                    #importance = $Priority
                    #isReadReceiptRequested = $RequestReadReceipt.IsPresent
                    #isDeliveryReceiptRequested = $RequestDeliveryReceipt.IsPresent
                }
                #saveToSentItems = -not $DoNotSaveToSentItems.IsPresent
                #saveToSentItems = $false
                saveToSentItems = $SaveToSentItems.IsPresent
            }
            Write-Debug ($params.Values | Out-String)

            #Send-MgUserMail -UserId $From -Message $params
            try {
                Send-MgUserMail -UserId $From -BodyParameter $params
            } catch {
                throw "Failed to send mail: $($_.Exception.Message)"
            }

        }
        'SMTP' {
            # --- SMTP
            #Send-MKMailMessage -To "admin@contoso.onmicrosoft.com" -From "AutomateB@contoso.onmicrosoft.com" -Subject "Test" -SmtpServer "smtp.office365.com" -Credential $credential -Port 25
            # > Send-MKMailMessage: as8758.net SMTPBLOCKER ESMTP Service not available
            #Send-MKMailMessage -To "admin@contoso.onmicrosoft.com" -From "AutomateB@contoso.onmicrosoft.com" -Subject "Test" -SmtpServer "smtp.office365.com" -Credential $credential -Port 587
            # > Send-MKMailMessage: 535: 5.7.139 Authentication unsuccessful, the request did not meet the criteria to be authenticated successfully
            # > Send-MKMailMessage: 535: 5.7.139 Authentication unsuccessful, the request did not meet the criteria to be authenticated successfully.

            If (!(Get-Package MailKit)){
                #
                Find-Package -Name 'MailKit' -Source 'https://www.nuget.org/api/v2' | Install-Package #-Verbose
            }

            #Get-Package MailKit
            #(Get-Package -ProviderName NuGet -Name 'MailKit') | fl *
            $folderNameMail = Split-Path (Get-Package -ProviderName NuGet -Name 'MailKit').Source -Parent
            $folderNameMime = Split-Path (Get-Package -ProviderName NuGet -Name 'MimeKit').Source -Parent
            #C:\Program Files\PackageManagement\NuGet\Packages\MailKit.4.11.0\MailKit.4.11.0.nupkg
            # C:\Program Files\PackageManagement\NuGet\Packages\MailKit.4.11.0

            [System.Reflection.Assembly]::LoadFile("$($folderNameMail)\lib\net48\MailKit.dll") > $null
            [System.Reflection.Assembly]::LoadFile("$($folderNameMime)\lib\net48\MimeKit.dll") > $null
            Add-Type -Path "$($folderNameMail)\lib\net48\MailKit.dll"
            Add-Type -Path "$($folderNameMime)\lib\net48\MimeKit.dll"

            #$SMTP = New-Object MailKit.Net.Smtp.SmtpClient


            #[MailKit.Net.Smtp.SmtpClient]
            $smtpClient = [MailKit.Net.Smtp.SmtpClient]::new()

            # Set TLS to automatically negotiate security
            #$UseSSL = $false
            if ($UseSSL -and $Port -ne "587"){
                $SSLAuto = [MailKit.Security.SecureSocketOptions]::SslOnConnect
            } else {
                $SSLAuto = [MailKit.Security.SecureSocketOptions]::StartTlsWhenAvailable
                #$SSLAuto = [MailKit.Security.SecureSocketOptions]::Auto
                # https://mimekit.net/docs/html/T_MailKit_Security_SecureSocketOptions.htm
            }

            #$smtpClient.Connect($channel.Definition.host, $channel.Definition.port, $channel.Definition.ssl) # $SMTP.Connect('smtp.gmail.com', 587, $False)
            #$smtpClient.Connect($SmtpServer, $Port, $UseSSL) # $SMTP.Connect('smtp.gmail.com', 587, $False)
            $smtpClient.Connect($SmtpServer, $Port, $SSLAuto)

            #$smtpClient.Authenticate($channel.Definition.username, ( Convert-SecureToPlaintext -String $channel.Definition.password)) # $SMTP.Authenticate('myemail1@gmail.com', 'appspecificpassword' )
            #$smtpClient.Authenticate($Username, $Password) # $SMTP.Authenticate('myemail1@gmail.com', 'appspecificpassword' )

            # $token.AccessToken = OAuth2 Token (replace this with your actual OAuth2 token)
            #$username = "test"
            #$username = $token.TokenData.unique_name
            $username = $token.TokenData.upn

            # Create an OAuth2 mechanism for authentication
            ##$oAuth2 = [MailKit.Security.SaslMechanismOAuth2]::new($AuthToken.Account.Username, $AuthToken.AccessToken)
            #$oAuth2 = New-Object MailKit.Security.SaslMechanismOAuth2 -ArgumentList $channel.Definition.username, $token.AccessToken
            $oAuth2 = New-Object MailKit.Security.SaslMechanismOAuth2 -ArgumentList $username, $token.AccessToken
            #$oAuth2 = New-Object MailKit.Security.SaslMechanismOAuthBearer -ArgumentList $username, $token.AccessToken

            Write-Verbose ($oAuth2.Credentials | Out-String) -Verbose
            #Write-Verbose ($oAuth2.Credentials | fl * | Out-String) -Verbose

            #$smtpClient.Authenticate($oauth2Mechanism)
            $smtpClient.Authenticate($oAuth2)
            #MethodInvocationException: Exception calling "Authenticate" with "1" argument(s): "451: 4.7.0 Temporary server error. Please try again later. PRX5 [ZR2P278CA0086.CHEP278.PROD.OUTLOOK.COM 2025-03-31T01:06:59.921Z 08DD6E37F3A552D5]"

            # Create the email message (MimeMessage)
            $message = [MimeKit.MimeMessage]::new()

            # Set the 'From' address
            $from = [MimeKit.MailboxAddress]::new('Your Name', $From)
            $message.From.Add($from)

            # Set the 'To' address
            $to = [MimeKit.MailboxAddress]::new('Recipient Name', $To)
            $message.To.Add($to)

            # Set the subject and body of the email
            #$message.Subject = "Your Email Subject"
            $message.Subject = $Subject
            $messageBody = [MimeKit.TextPart]::new("plain")
            #$messageBody.Text = "This is the email body content."
            $messageBody.Text = $Body
            $message.Body = $messageBody

            # Proceed with sending email
            $smtpClient.Send($message)
            # MethodInvocationException: Exception calling "Send" with "1" argument(s): "5.7.57 Client not authenticated to send mail. [ZR0P278CA0195.CHEP278.PROD.OUTLOOK.COM 2025-03-31T00:59:51.228Z 08DD6FAFE0C04FAE]"

            # Disconnect after sending the email
            $smtpClient.Disconnect($True)
            $smtpClient.Dispose()


        }
        'TEAMS' {
            Write-Verbose "Development: ToDo"

        }
        default {
            Write-Debug "Invalid modus specified"
        }
    }
}

function Enable-MailMessageAlias {
    <#
    .SYNOPSIS
        Enables alias for Send-MailMessage command.
    .DESCRIPTION
        Enables Send-MailMessage command alias in the current PowerShell session.
    .EXAMPLE
        Enable-MailMessageAlias
    .INPUTS
        None
    .OUTPUTS
    .NOTES
    #>


    if (-not $DisableTelemetry) {
        Write-Telemetry -EventName "EnableMailMessageAlias"
    }

    #Reference:
    # https://learn.microsoft.com/en-us/powershell/module/microsoft.entra/enable-entraazureadalias?view=entra-powershell

    Set-Alias -Name Send-MailMessage -Value Send-ModernMailMessage -Scope Global -Force
    Set-Alias -Name Register-MailMessageEntraIDApp -Value Register-ModernMailMessageEntraIDApp -Scope Global -Force
    Set-Alias -Name Register-MailMessageApp -Value Register-ModernMailMessageEntraIDApp -Scope Global -Force
}

function Write-Telemetry {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [ValidateSet("RegisterModernMailMessageEntraIDApp","SendModernMailMessage","EnableMailMessageAlias")]
        [string]
        $EventName
    )
    #$EventName = "SendModernMailMessage"
    Write-Verbose "Sending telemetry event: $EventName"

    $tenantId = Get-MgContext | Select-Object -ExpandProperty TenantId
    if (-not $tenantId) {
        $tenantId = "unknown"
    }

    $jsonData = @{
        "api_key" = "c0cd5aa997bde6dd291d06729c7548a7"
        "events" = @{
            "user_id" = $tenantId
            #"device_id" = "$($env:ComputerName)"
            "device_id" = $([BitConverter]::ToString([System.Security.Cryptography.SHA256]::Create().ComputeHash([System.Text.Encoding]::UTF8.GetBytes($env:ComputerName))).Replace('-', '').ToLower())
            "event_type"= $EventName
            "app_version" = "0.1.1"
            "platform" = "PowerShell $($PSVersionTable.PSVersion)"
            "os_name" = (Get-CimInstance Win32_OperatingSystem).Caption
            "language" = (Get-Culture).Name
            "ip" = '$remote'
        }
    }

    # Convert the data to JSON format
    $jsonBody = $jsonData | ConvertTo-Json

    # Define the URL
    $url = "https://api.eu.amplitude.com/2/httpapi"

    # Send the POST request
    try {
        Invoke-RestMethod -Uri $url -Method Post -ContentType "application/json" -Body $jsonBody | Out-Null
    } catch {
        Write-Verbose $_
    }
}

Export-ModuleMember -Function @("Send-ModernMailMessage", "Register-ModernMailMessageEntraIDApp","Enable-MailMessageAlias")