Email.psm1

<#
.SYNOPSIS
    This function verifies if an email address follows a valid pattern.
.PARAMETER emailAddress
    The email address to verify.
.EXAMPLE
    Test-EmailAddressValidity -EmailAddress "mailbox@domain.com"
#>

function Test-EmailAddressValidity {
    [CmdletBinding()]
    [OutputType([Bool])]
    param (
        # The email address to verify
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$emailAddress
    )

    # Check for null/whitespce
    if ([String]::IsNullOrWhiteSpace($emailAddress)) {
        return $false
    }

    # Try to cast to MailAddress type
    try {
        $null = [MailAddress]$emailAddress
        return $true
    }

    # Exception means email is not valid
    catch {
        return $false
    }
}

<#
.SYNOPSIS
    This function verifies if a domain name follows a valid pattern.
#>

function Test-DomainValidity {
    [CmdletBinding()]
    [OutputType([Bool])]
    param (
        # The domain to verify
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$domain
    )

    # Check against basic regex
    return [Regex]::New("^([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,}$").IsMatch($domain)
}

<#
.SYNOPSIS
    This function extracts the domain portion of an email address.
.DESCRIPTION
    This function extracts the domain portion of an email address.
    The domain is the portion of the email after the '@' character.
    If the email is invalid, an empty string is returned.
.PARAMETER emailAddress
    The email address which the domain will be extracted from.
.EXAMPLE
    Get-EmailAddressDomain -EmailAddress "mailbox@domain.com"
#>

function Get-EmailAddressDomain {
    [CmdletBinding()]
    [OutputType([String])]
    param (
        # The email address which the domain will be extracted from.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$emailAddress
    )

    # Check email validity
    if (!(Test-EmailAddressValidity -EmailAddress $emailAddress)) {
        return ""
    }

    # Extract domain
    return $emailAddress.Remove(0, $emailAddress.IndexOf('@') + 1)
}

<#
.SYNOPSIS
    This function extracts the username portion of an email address.
.DESCRIPTION
    This function extracts the username portion of an email address.
    The domain is the portion of the email before the '@' character.
    If the email is invalid, an empty string is returned.
.PARAMETER emailAddress
    The email address which the username will be extracted from.
.EXAMPLE
    Get-EmailAddressUsername -EmailAddress "mailbox@domain.com"
#>

function Get-EmailAddressUsername {
    [CmdletBinding()]
    [OutputType([String])]
    param (
        # The email address which the domain will be extracted from.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$emailAddress
    )

    # Check email validity
    if (!(Test-EmailAddressValidity -EmailAddress $emailAddress)) {
        return ""
    }

    # Extract domain
    return $emailAddress.Substring(0, $emailAddress.IndexOf('@'))
}

<#
.SYNOPSIS
    This function sends an email containing optional attachments.
.DESCRIPTION
    This function sends an email containing optional attachments.
    It returns if the email was sent successfully.
#>

function Send-Email {
    [CmdletBinding(PositionalBinding=$true)]
    [OutputType([Bool])]
    param (
        # The credentials which will be used to send the email.
        [Parameter(Mandatory=$true)]
        [ValidateNotNull()]
        [PSCredential]$emailCredentials,

        # The email smtp server.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$smtpServer,

        # The port number on the email smtp server.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$portNumber,

        # The destination email address which the email will be sent.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript({ Test-EmailAddressValidity $_ })]
        [String]$destinationEmailAddress,

        # The subject of the email.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$emailSubject,

        # The body of the email.
        [Parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [String]$emailBody,

        # An array containing the paths of the files to attach to the email.
        [Parameter(Mandatory=$false)]
        [ValidateNotNull()]
        [PSObject[]]$attachmentFilePaths
    )

    # Compress the attachments into a single .zip file
    if ($attachmentFilePaths) {
        try {
            $attachmentFilePaths = ConvertTo-Array $attachmentFilePaths
            $filePath = "$($env:TEMP)\$(New-Guid).zip"
            Compress-Archive -Path $attachmentFilePaths -DestinationPath $filePath -CompressionLevel Optimal
            $attachmentFile = Get-Item $filePath
            Write-Information "Attaching archive '$($attachmentFile.FullName)' containing the attachments to the email."
        }
        catch {
            Write-Error "Error while compressing attachments into a single .zip file.`r`n$($_.Exception.Message)"
            return $false
        }

        if (!$attachmentFile) {
            Write-Error "Failed to compress attachments into a single .zip file.`r`n$($_.Exception.Message)"
            return $false
        }
    }

    # Create hash table for params
    $sendMailMessageParams = @{
        From        = $emailCredentials.Username
        Credential  = $emailCredentials
        SmtpServer  = $smtpServer
        Port        = $portNumber
        To          = $destinationEmailAddress
        Subject     = $emailSubject
        Body        = $emailBody
    }
    if ($attachmentFile) {
        $sendMailMessageParams.Add("Attachments", $attachmentFile.FullName)
    }

    # Send the email
    try {
        Write-Information "Sending the email to '$($destinationEmailAddress)'."
        Send-MailMessage @sendMailMessageParams -UseSsl
    }
    catch {
        Write-Error "Error while sending the email to '$($destinationEmailAddress)'.`r`n$($_.Exception.Message)"
        return $false
    }
    return $true
}