Notice: Due to size constraints and loading performance considerations, scripts referenced in blog posts are not attached directly. To request access, please complete the following form: Script Request Form Note: A Google account is required to access the form.
Disclaimer: I do not accept responsibility for any issues arising from scripts being run without adequate understanding. It is the user's responsibility to review and assess any code before execution. More information

From Blue Lines of Death to Email Success: My Outlook Nightmare

E-mail campaign for our internal iPhone 16e rollout, I thought it would be straightforward. How wrong I was. What started as a simple HTML email became a deep dive into the quirks of Outlook rendering, PowerShell SMTP limitations, Active Directory integration - simple idea, complex outcomes!

Visual Results

This is the email that was sent to people letting them know about a new phone, however lets look later in the post about the "Click here to upgrade"


The Challenge: More Than Just an Email

Our IT department needed to announce the availability of iPhone 16e devices to eligible employees. The goals were clear, which ironically also looked like phishing email requirements (maybe this could be weaponised this later on)

  • Create urgency around limited availability
  • Drive clicks to the upgrade portal
  • Ensure 100% compatibility across email clients
  • Target different departments with appropriate messaging
  • Automate the process using existing Active Directory data

What I didn't anticipate was how this would become a masterclass in email client compatibility, organizational data integration, and corporate psychology or everyone wanting the next "corporate" standard phone.

Initial Design: The Web vs. Email Reality Check

I started with what I thought was a bulletproof approach - a modern HTML email template with CSS styling:

<!DOCTYPE html>
<html lang="en">
<head>
    <style>
        .container {
            max-width: 600px;
            margin: 0 auto;
            background-color: #ffffff;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
            border-radius: 12px;
        }
        .upgrade-button {
            background-color: #0071e3;
            color: white;
            padding: 16px 24px;
            border-radius: 8px;
        }
    </style>
</head>

This looked perfect in web browsers and Outlook Web Access. Then I tested it in Outlook desktop it went a little wrong, the button disappeared, rounded corners vanished, and checkmarks turned into blue lines, the problem was Outlook's awful rendering engine.

The Outlook Compatibility Nightmare

Problem 1: The Invisible Button

My first major issue was the upgrade button simply not appearing in Outlook desktop:

<!-- This DOESN'T work in Outlook -->
<a href="#" class="upgrade-button">CLICK HERE TO UPGRADE</a>

This only successfully worked when we used table-based buttons with inline styling:

<!-- This WORKS in Outlook -->
<table border="0" cellpadding="0" cellspacing="0" width="300" bgcolor="#0071e3">
    <tr>
        <td align="center" style="padding: 12px 30px;">
            <a href="#" style="color: #ffffff; display: block; font-family: Arial, 
            sans-serif; font-size: 18px; font-weight: bold; text-decoration: none;">
            CLICK HERE TO UPGRADE</a>
        </td>
    </tr>
</table>

Problem 2: The Blue Line Mystery

The benefit checkmarks were rendering as blue lines instead of proper checkmarks:

<!-- This created blue lines in Outlook -->
<div style="background-color: #0071e3; border-radius: 12px;">✓</div>

This again required nested table approach with explicit dimensions included:

<!-- This renders properly in Outlook -->
<table border="0" cellpadding="0" cellspacing="0" width="24" height="24" bgcolor="#0071e3">
    <tr>
        <td align="center" valign="middle" style="color: #ffffff; font-weight: bold;">✓</td>
    </tr>
</table>

Problem 3: Image Embedding Issues

Initially, I tried base64 encoding for the iPhone image:

<img src="data:image/jpeg;base64,/9j/4AAQSkZJRgABA..." />

While this worked in web clients, Outlook had rendering issues. The solution was using Content-ID references with PowerShell attachments:

<img src="cid:iPhoneImage" alt="iPhone 16e" style="display: block; width: 100%;" />

With the corresponding PowerShell code:

# Create attachment with Content-ID
$attachment = New-Object System.Net.Mail.Attachment("iphone-image.jpg")
$attachment.ContentId = "iPhoneImage"
$attachment.ContentDisposition.Inline = $true
$message.Attachments.Add($attachment)

Hyperlink : Click here to upgrade

This is where it may have got fun as this link could be official or part of an internal phishing test which makes if more spicy, especially if these emails are rolled out with the actual rollout of distribution of iPhones.

I did wonder if fear of missing out (FOMO) would cause people to click on the link without actually checking that link completely due to "wants" of a new phone, which means the moment the link for this post is set to, which means it does nothing as below:

        <td align="center" style="padding: 12px 30px;">
            <a href="#" style="color: #ffffff; display: block; font-family: Arial, 
            sans-serif; font-size: 18px; font-weight: bold; text-decoration: none;">
            CLICK HERE TO UPGRADE</a>
There is no point turning this information a credential phishing website as that would undermine trust and confidence, so lets give that a link on an IIS web server that is setup to log visit from integrated credentials:
            <a href="https://wwwsrv1.bear.local/iphone16upgrade" 
            style="color: #ffffff; display: block; font-family: Arial, 
Then on the web server (IIS) the backend for processing we could create an IIS website that uses Windows Authentication with Negotiate as the provider as below:



You will then end up with a IIS log entry like this where you can easily identify the user that has clicked on the email from the log, see below:
2025-06-23 16:06:29 <source_ip> GET /iPhone16e/ - 
443 BEAR\lee 10.84.77.259 Mozilla/5.0+
(Windows+NT+10.0;+Win64;+x64)+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/137.0.0.0
+Safari/537.36+Edg/137.0.0.0 https://wwwsrv1.bear.local/iphone16upgrade 200 0 0 17
This means we can now track how has clicked on the link with the native IIS logs, so you can then report on those IIS logs based on people that have clicked on the email, further more if you are into tracking then you can send an e-mail with a "image beacon" embedded into it that will then also report this same "tracking" in the logs.
2025-06-23 16:06:29 <source_ip> GET /iPhone16e/beacon.png - 
443 BEAR\lee 10.245.161.136 Mozilla/5.0+(Windows+NT+10.0;+Win64;+x64)
+AppleWebKit/537.36+(KHTML,+like+Gecko)+Chrome/137.0.0.0+Safari/537.36+Edg/137.0.0.0 
https://www.srv1.bear.local/iphone16upgrade 200 0 0 230
This will then tell us that the beacon.png has been viewed by the user as they open or view the emails with "download images dynamically" also enabled, which all employees will load the same "beacon.png".

I then wondered if we could change the content of the e-mail for certain departments based on the OU value they have as the user account, so lets dig a little deeper into that outcome shall we, and that sounds fund to code, if you are interested in that then please read on.

Organizational Integration: Department-Based Dynamic Content

Once I had the technical issues resolved, I realized we needed a more sophisticated approach. Different departments should receive different messaging - IT and Sales teams needed an "eligible" message, while other departments needed more informational content.

Rather than manually managing department lists, I implemented dynamic content generation based on Active Directory organizational units (OUs). This allowed for:

  • Version A (Priority Departments): "You're Now Eligible to Upgrade!" - Personal, urgent messaging
  • Version B (General Departments): "iPhone 16e Now Available" - Informational, check-eligibility messaging

Active Directory Integration

The key breakthrough was extracting department information directly from Distinguished Names (DNs) in Active Directory:

function Get-DepartmentFromDN($distinguishedName) {
    Write-Verbose "Processing DN: $distinguishedName"
    
    # Split the DN into components
    $dnComponents = $distinguishedName -split ","
    
    # Find OU components (excluding the CN)
    $ouComponents = $dnComponents | Where-Object { $_ -like "OU=*" } | ForEach-Object {
        $_.Substring(3)  # Remove "OU=" prefix
    }
    
    # Define department keywords to look for
    $departmentKeywords = @{
        "IT" = @("IT", "Information Technology", "Technology", "Technical")
        "Sales" = @("Sales", "Business Development", "Commercial")
        "Marketing" = @("Marketing", "Communications", "PR")
        "Finance" = @("Finance", "Accounting", "Financial")
        "HR" = @("HR", "Human Resources", "People", "Personnel")
        "Management" = @("Management", "Executive", "Leadership", "Directors")
        "Operations" = @("Operations", "Ops", "Operational")
    }
    
    # Check each OU component against department keywords
    foreach ($ou in $ouComponents) {
        foreach ($dept in $departmentKeywords.Keys) {
            foreach ($keyword in $departmentKeywords[$dept]) {
                if ($ou -like "*$keyword*") {
                    Write-Verbose "Matched '$ou' to department '$dept' via keyword 
                    '$keyword'"
                    return $dept
                }
            }
        }
    }
    
    # Fallback to first meaningful OU
    $meaningfulOUs = $ouComponents | Where-Object { 
        $_ -notlike "*Users*" -and 
        $_ -notlike "*Computers*" -and 
        $_ -notlike "*Service*"
    }
    
    if ($meaningfulOUs.Count -gt 0) {
        return $meaningfulOUs[0]
    }
    
    return "Unknown"
}

Dynamic Email Variant Selection

Based on the department extracted from AD, I implemented variant selection:

function Get-EmailVariant($department) {
    # High-priority departments get the "eligible" message
    $highPriorityDepts = @("IT", "Management", "Sales", "Finance")
    
    if ($department -in $highPriorityDepts) {
        return @{
            Subject = "You're Now Eligible to Upgrade!"
            Header = "YOU'RE NOW ELIGIBLE<br>TO UPGRADE!"
            MainText = "you're now eligible to upgrade your work phone"
            Urgency = "This upgrade program is available for a limited time. 
            Complete your request by June 15, 2025 to secure your new device."
            ButtonText = "CLICK HERE TO UPGRADE"
        }
    } else {
        return @{
            Subject = "iPhone 16e Now Available"
            Header = "iPHONE 16e<br>NOW AVAILABLE"
            MainText = "the iPhone 16e is now available for eligible employees"
            Urgency = "Contact IT to check your upgrade eligibility and availability."
            ButtonText = "CHECK ELIGIBILITY"
        }
    }
}

Template with Dynamic Placeholders

The HTML template was enhanced to support dynamic content injection:

<!-- Header section with dynamic content -->
<tr>
    <td align="center" style="padding: 30px 20px;">
        <h1 style="font-size: 36px; font-weight: bold; margin: 0; color: #1d1d1f; 
        text-transform: uppercase;">
            {{HEADER}}
        </h1>
    </td>
</tr>

<!-- Main content with personalized messaging -->
<tr>
    <td style="padding: 20px;">
        <img src="cid:iPhoneImage" alt="iPhone 16e" style="display: block; width: 100%;" />
        
        <h2 style="font-size: 36px; font-weight: bold; margin: 0; color: #1d1d1f;">
        iPhone 16e</h2>
        <p style="font-size: 24px; margin: 5px 0 20px; color: #0071e3;">Now in Stock</p>
        
        <p style="font-size: 16px; margin: 20px 0; line-height: 1.5;">
            The iPhone 16e has recently come into stock and {{MAIN_TEXT}}.
        </p>
        
        <!-- Benefits section stays consistent -->
        
        <p style="font-size: 16px; margin: 20px 0; line-height: 1.5;">
            {{URGENCY}}
        </p>
        
        <!-- Dynamic button text -->
        <table border="0" cellpadding="0" cellspacing="0" width="300" bgcolor="#0071e3">
            <tr>
                <td align="center" style="padding: 12px 30px;">
                    <a href="#" style="color: #ffffff; display: block; font-family: 
                    Arial, sans-serif; font-size: 18px; font-weight: bold; 
                    text-decoration: none;">
                        {{BUTTON_TEXT}}
                    </a>
                </td>
            </tr>
        </table>
    </td>
</tr>

Visuals from the Dynamic Content delivery

If you do go down the dynamic emails to certain departments there you can also pull some very nice reports from the IIS logs, first you will need the log file from IIS then from that 

.\Analyse-iPhone16Basic.ps1 -LogFilePath u_ex220817.log

This will then give you the basic report that will track opens, beacons and URL clicks as below:

However if you want to go a little deeper in the analysis you can run this deatailed version:

.\Analyse-iPhone16Basic.ps1 -LogFilePath u_ex220817.log

This will break this down until more details statistics as below:

Then lower down you will get a user breakdown:


Script : 

Here's my final PowerShell script however you will need to update the sections in bold which include the base HTML and PNG of the iPhone 16e, also do not forget to update the SMTP server details.

# Import required modules
Import-Module ActiveDirectory

# Email configuration
$smtpServer = "smtp.bear.local"
$smtpPort = 25

# Enhanced user processing with DN handling
function Process-ADUsers {
    $adUsers = Get-ADUser -Filter {
        Enabled -eq $true -and 
        EmailAddress -like "*@company.com"
    } -Properties EmailAddress, DistinguishedName, GivenName, Surname, Department
    
    Write-Host "Retrieved $($adUsers.Count) users from Active Directory"
    
    # Process each user
    $processedUsers = foreach ($user in $adUsers) {
        $department = if ($user.Department) {
            $user.Department
        } else {
            Get-DepartmentFromDN $user.DistinguishedName
        }
        
        [PSCustomObject]@{
            Email = $user.EmailAddress
            FirstName = $user.GivenName
            LastName = $user.Surname
            Department = $department
            DistinguishedName = $user.DistinguishedName
            FullName = "$($user.GivenName) $($user.Surname)"
        }
    }
    
    return $processedUsers
}

# Main execution
$users = Process-ADUsers

# Group by department for reporting
$departmentGroups = $users | Group-Object Department | Sort-Object Name
Write-Host "`nDepartment Distribution:" -ForegroundColor Green
foreach ($group in $departmentGroups) {
    Write-Host "  $($group.Name): $($group.Count) users" -ForegroundColor Cyan
}

# Send personalized emails
foreach ($user in $users) {
    if (-not $user.Email) {
        Write-Warning "Skipping user $($user.FullName) - no email address"
        continue
    }
    
    try {
        # Get appropriate email variant
        $variant = Get-EmailVariant $user.Department
        
        # Load and customize template
        $htmlTemplate = Get-Content ".\email-template.html" -Raw
        $personalizedHtml = $htmlTemplate -replace "{{HEADER}}", $variant.Header
        $personalizedHtml = $personalizedHtml -replace "{{MAIN_TEXT}}", $variant.MainText
        $personalizedHtml = $personalizedHtml -replace "{{URGENCY}}", $variant.Urgency
        $personalizedHtml = $personalizedHtml -replace "{{BUTTON_TEXT}}", 
        $variant.ButtonText
        
        # Create email message
        $message = New-Object System.Net.Mail.MailMessage
        $message.From = "phone.requests@bythepowerofgreyskull.com"
        $message.To.Add($user.Email)
        $message.Subject = $variant.Subject
        $message.IsBodyHtml = $true
        $message.Body = $personalizedHtml
        
        # Add iPhone image with Content-ID
        $attachment = New-Object System.Net.Mail.Attachment(".\iphone16e.jpg")
        $attachment.ContentId = "iPhoneImage"
        $attachment.ContentDisposition.Inline = $true
        $message.Attachments.Add($attachment)
        
        # Send email
        $smtpClient = New-Object System.Net.Mail.SmtpClient($smtpServer, $smtpPort)
        $smtpClient.Send($message)
        
        Write-Host "✓ Sent '$($variant.Subject)' to $($user.FullName) 
        ($($user.Department))" 
        -ForegroundColor Green
        
        $message.Dispose()
        
    } catch {
        Write-Error "✗ Failed to send to $($user.Email): $($_.Exception.Message)"
    }
}
Previous Post Next Post

نموذج الاتصال