Option Explicit
Sub CreateEmailContentViewer()
Dim objOutlook As Outlook.Selection
Dim objMail As Outlook.MailItem
Dim fso As Object
Dim htmlFile As Object
Dim filePath As String
Dim mailCount As Integer
Dim imageUrls As Collection
On Error Resume Next
' Initialize collection for unique URLs
Set imageUrls = New Collection
' Create file system object
Set fso = CreateObject("Scripting.FileSystemObject")
' Set file path to Desktop
filePath = Environ("USERPROFILE") & "\Desktop\Image_View_SME.html"
' Create HTML file
Set htmlFile = fso.CreateTextFile(filePath, True)
' Write HTML header
WriteHeader htmlFile
' Get selected items
Set objOutlook = Application.ActiveExplorer.Selection
' Create email container
htmlFile.WriteLine "<div class='email-container'>"
' In the CreateEmailContentViewer sub, replace the email section part with this:
' Process emails
mailCount = 0
For Each objMail In objOutlook
mailCount = mailCount + 1
' Start new email section
htmlFile.WriteLine "<div class='email-section'>"
htmlFile.WriteLine "<div class='email-header'>"
htmlFile.WriteLine "<h2>Email #" & mailCount & ": " & objMail.Subject &
"</h2>"
htmlFile.WriteLine "<p>From: " & objMail.SenderName & "</p>"
htmlFile.WriteLine "<p>Date: " & Format(objMail.ReceivedTime, "mm/dd/yyyy
hh:mm AM/PM") & "</p>"
' Add dispute section
htmlFile.WriteLine "<div class='dispute-section'>"
htmlFile.WriteLine " <label class='checkbox-container'>Mark for Dispute"
htmlFile.WriteLine " <input type='checkbox' id='dispute-check-" &
mailCount & "' onchange='toggleDisputeComment(" & mailCount & ")'>"
htmlFile.WriteLine " <span class='checkmark'></span>"
htmlFile.WriteLine " </label>"
' Updated dispute comment section to allow saving directly into HTML (in
browser view)
htmlFile.WriteLine " <div id='dispute-comment-" & mailCount & "'
class='dispute-comment' style='display:none;'>"
htmlFile.WriteLine " <textarea id='comment-" & mailCount & "'
placeholder='Enter dispute comment...'></textarea><br>"
htmlFile.WriteLine " <button onclick='saveDispute(" & mailCount &
")' class='save-btn'>Save Comment</button>"
htmlFile.WriteLine " </div>"
htmlFile.WriteLine "</div>"
htmlFile.WriteLine "</div>"
' Email content with hyperlinks
htmlFile.WriteLine "<div class='email-content'>"
htmlFile.WriteLine "<div class='text-content'>"
htmlFile.WriteLine ConvertTextWithHyperlinks(objMail.Body,
objMail.htmlBody)
htmlFile.WriteLine "</div>"
' Image section
htmlFile.WriteLine "<div class='scroll-hint'>? Scroll horizontally to view
all images ?</div>"
htmlFile.WriteLine "<div class='image-section'>"
' Extract and display images - Using the provided subroutine
ExtractAndDisplayImages objMail, htmlFile, imageUrls
htmlFile.WriteLine "</div>" ' Close image-section
htmlFile.WriteLine "</div>" ' Close email-content
htmlFile.WriteLine "</div>" ' Close email-section
htmlFile.WriteLine "<hr>"
Next objMail
htmlFile.WriteLine "</div>" ' Close email-container
' Write image controls
WriteImageControls htmlFile
' Write footer
WriteFooter htmlFile
htmlFile.Close
' Open the HTML file
CreateObject("WScript.Shell").Run filePath
MsgBox "HTML file created at: " & filePath & vbCrLf & _
"Total emails processed: " & mailCount, vbInformation
End Sub
Function ConvertTextWithHyperlinks(plainBody As String, htmlBody As String) As
String
Dim result As String
Dim regex As Object
Dim matches As Object
Dim match As Object
result = Replace(plainBody, vbCrLf, "<br>")
' Create regex object
Set regex = CreateObject("VBScript.RegExp")
' Pattern for URLs
regex.Pattern = "(https?:\/\/[^\s<>""'\)]+)"
regex.Global = True
regex.IgnoreCase = True
' Find matches
Set matches = regex.Execute(result)
' Replace URLs with hyperlinks
Dim i As Long
For i = matches.Count - 1 To 0 Step -1
Set match = matches(i)
Dim url As String
Dim displayText As String
url = match.Value
' Clean up URL
url = Replace(url, """", "")
url = Replace(url, "'", "")
url = Replace(url, ">", "")
url = Replace(url, "<", "")
' Determine display text based on URL
displayText = GetDisplayTextForUrl(url)
' Create hyperlink
Dim hyperlink As String
hyperlink = "<a href='" & url & "' target='_blank' title='" & url & "'>" &
displayText & "</a>"
' Replace in result
result = Left(result, match.FirstIndex) & hyperlink & Mid(result,
match.FirstIndex + match.Length + 1)
Next i
ConvertTextWithHyperlinks = result
End Function
Function GetDisplayTextForUrl(url As String) As String
' Function to determine what text to display for different types of URLs
' Check for retail/product pages
If InStr(1, url, "amazon.de/dp/") > 0 Then
GetDisplayTextForUrl = "Product Link"
ElseIf InStr(1, url, "retail.page") > 0 Then
GetDisplayTextForUrl = "Retail Page"
ElseIf InStr(1, url, "dispute") > 0 Then
GetDisplayTextForUrl = "Dispute Link"
ElseIf InStr(1, url, "image-downloads") > 0 Then
GetDisplayTextForUrl = "Image Link"
Else
GetDisplayTextForUrl = "Click here"
End If
End Function
' Subroutine to extract and display images, now including a URL count in the
caption
Sub ExtractAndDisplayImages(mail As Outlook.MailItem, htmlFile As Object, imageUrls
As Collection)
Dim regex As Object
Dim matches As Object
Dim match As Object
Dim url As String
Dim htmlBody As String
Dim urlCount As Long
' Get HTML body
htmlBody = mail.htmlBody
' Create regex object
Set regex = CreateObject("VBScript.RegExp")
' Pattern for image URLs
regex.Pattern = "https?:\/\/[^\s<>""']+(?:jpg|jpeg|png|gif|bmp|data\.jpg)[^\
s<>""']*"
regex.Global = True
regex.IgnoreCase = True
' Find matches in both HTML body and plain text body
Set matches = regex.Execute(htmlBody)
If matches.Count = 0 Then
Set matches = regex.Execute(mail.Body)
End If
' Initialize URL counter
urlCount = 0
' Process matches
For Each match In matches
url = match.Value
urlCount = urlCount + 1
' Clean up URL
url = Replace(url, """", "")
url = Replace(url, "'", "")
url = Replace(url, ">", "")
url = Replace(url, "<", "")
' Add URL to collection and display image
On Error Resume Next
imageUrls.Add url, CStr(url)
htmlFile.WriteLine "<div class='image-box'>"
htmlFile.WriteLine " <img src='" & url & "' onclick='enlargeImage(this)'
onerror='handleImageError(this)'>"
' Updated image caption to show URL count
htmlFile.WriteLine " <div class='image-caption'>URL #" & urlCount &
"</div>"
htmlFile.WriteLine "</div>"
On Error GoTo 0
Next match
End Sub
Sub WriteHeader(htmlFile)
htmlFile.WriteLine "<!DOCTYPE html>"
htmlFile.WriteLine "<html>"
htmlFile.WriteLine "<head>"
htmlFile.WriteLine " <title>SUSTAINABLE PACKAGING OPERATIONS - IMAGE VIEW
PLATFORM</title>"
htmlFile.WriteLine " <style>"
htmlFile.WriteLine " body { font-family: Arial, sans-serif; margin:
20px; background-color: #f5f5f5; }"
htmlFile.WriteLine " .header { text-align: center; padding: 20px;
background-color: white; border-radius: 8px; margin-bottom: 20px; box-shadow: 0 2px
4px rgba(0,0,0,0.1); }"
' Style for the new dispute summary section
htmlFile.WriteLine " .dispute-summary-section { background-color:
#fff3cd; border: 1px solid #ffeeba; border-radius: 8px; padding: 15px; margin-
bottom: 20px; box-shadow: 0 2px 4px rgba(0,0,0,0.1); }"
htmlFile.WriteLine " .dispute-summary-section h3 { margin-top: 0; color:
#664d03; }"
htmlFile.WriteLine " .dispute-summary-section p { margin-bottom: 5px; }"
htmlFile.WriteLine " .email-container { max-width: 1200px; margin: 0
auto; }"
htmlFile.WriteLine " .email-section { background-color: white; margin:
20px 0; padding: 20px; border-radius: 8px; box-shadow: 0 2px 4px
rgba(0,0,0,0.1); }"
htmlFile.WriteLine " .email-header { border-bottom: 1px solid #eee;
margin-bottom: 15px; padding-bottom: 15px; }"
htmlFile.WriteLine " .email-content { display: block; }"
htmlFile.WriteLine " .text-content { margin-bottom: 20px; white-space:
pre-wrap; }"
htmlFile.WriteLine " .text-content a { color: #0066cc; text-decoration:
none; }"
htmlFile.WriteLine " .text-content a:hover { text-decoration: underline;
}"
htmlFile.WriteLine " .text-content a:visited { color: #551A8B; }"
htmlFile.WriteLine " .image-section { overflow-x: auto; white-space:
nowrap; padding: 10px 0; }"
htmlFile.WriteLine " .image-box { display: inline-block; vertical-align:
top; margin: 10px; padding: 10px; background-color: #f8f9fa; border-radius: 4px;
text-align: center; max-width: 300px; }"
htmlFile.WriteLine " .image-box img { max-width: 280px; max-height:
280px; object-fit: contain; cursor: pointer; transition: transform 0.3s; }"
htmlFile.WriteLine " .image-box img:hover { transform: scale(1.05); }"
htmlFile.WriteLine " .image-caption { font-size: 12px; color: #666;
margin-top: 5px; word-wrap: break-word; white-space: normal; }"
htmlFile.WriteLine " .controls { position: fixed; top: 20px; right:
20px; background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px 4px
rgba(0,0,0,0.1); z-index: 100; }"
htmlFile.WriteLine " .image-controls { position: fixed; bottom: 20px;
left: 20px; background: white; padding: 15px; border-radius: 8px; box-shadow: 0 2px
4px rgba(0,0,0,0.1); z-index: 100; }"
htmlFile.WriteLine " button { padding: 8px 16px; margin: 5px;
background-color: #4CAF50; color: white; border: none; border-radius: 4px; cursor:
pointer; }"
htmlFile.WriteLine " button:hover { background-color: #45a049; }"
htmlFile.WriteLine " .slider { width: 200px; margin: 10px 0; }"
htmlFile.WriteLine " #overlay { display: none; position: fixed; top: 0;
left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); z-index: 1000; }"
htmlFile.WriteLine " #enlargedImg { max-width: 90%; max-height: 90%;
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }"
htmlFile.WriteLine " .scroll-hint { text-align: center; color: #666;
font-size: 12px; margin: 5px 0; }"
' Add these lines in the style section
htmlFile.WriteLine " .text-content a { color: #0066cc; text-decoration:
none; background-color: #f0f7ff; padding: 2px 6px; border-radius: 3px; }"
htmlFile.WriteLine " .text-content a:hover { background-color: #e0f0ff;
text-decoration: none; }"
htmlFile.WriteLine " .text-content a[title] { border-bottom: 1px dotted
#0066cc; cursor: help; }"
' Add these lines to the style section in WriteHeader
htmlFile.WriteLine " .dispute-section { margin: 10px 0; padding: 10px;
background-color: #f8f9fa; border-radius: 4px; }"
htmlFile.WriteLine " .checkbox-container { display: block; position:
relative; padding-left: 35px; margin-bottom: 12px; cursor: pointer; font-size:
16px; user-select: none; }"
htmlFile.WriteLine " .checkbox-container input { position: absolute;
opacity: 0; cursor: pointer; height: 0; width: 0; }"
htmlFile.WriteLine " .checkmark { position: absolute; top: 0; left: 0;
height: 25px; width: 25px; background-color: #eee; border-radius: 4px; }"
htmlFile.WriteLine " .checkbox-container:hover input ~ .checkmark
{ background-color: #ccc; }"
htmlFile.WriteLine " .checkbox-container input:checked ~ .checkmark
{ background-color: #2196F3; }"
htmlFile.WriteLine " .checkmark:after { content: ''; position: absolute;
display: none; }"
htmlFile.WriteLine " .checkbox-container input:checked
~ .checkmark:after { display: block; }"
htmlFile.WriteLine " .checkbox-container .checkmark:after { left: 9px;
top: 5px; width: 5px; height: 10px; border: solid white; border-width: 0 3px 3px 0;
transform: rotate(45deg); }"
htmlFile.WriteLine " .dispute-comment { margin-top: 10px; }"
htmlFile.WriteLine " .dispute-comment textarea { width: 100%; height:
100px; padding: 8px; margin-bottom: 10px; border: 1px solid #ddd; border-radius:
4px; resize: vertical; }"
htmlFile.WriteLine " .save-btn { background-color: #4CAF50; color:
white; padding: 8px 16px; border: none; border-radius: 4px; cursor: pointer; }"
htmlFile.WriteLine " .save-btn:hover { background-color: #45a049; }"
htmlFile.WriteLine " .saved-indicator { color: #4CAF50; margin-left:
10px; display: none; }"
htmlFile.WriteLine " </style>"
htmlFile.WriteLine "</head>"
htmlFile.WriteLine "<body>"
htmlFile.WriteLine " <div class='header'>"
htmlFile.WriteLine " <h1>SUSTAINABLE PACKAGING OPERATIONS - IMAGE VIEW
PLATFORM</h1>"
htmlFile.WriteLine " </div>"
' New section for dispute summary
htmlFile.WriteLine " <div id='dispute-summary' class='dispute-summary-
section' style='display:none;'></div>"
End Sub
Sub WriteImageControls(htmlFile)
htmlFile.WriteLine " <div class='controls'>"
htmlFile.WriteLine " <button onclick='showAllImages()'>Show
Images</button>"
htmlFile.WriteLine " <button onclick='resetImages()'>Reset</button>"
htmlFile.WriteLine " </div>"
htmlFile.WriteLine " <div class='image-controls'>"
htmlFile.WriteLine " <div>Brightness: <input type='range' class='slider'
min='0' max='200' value='100' onchange='adjustBrightness(this.value)'></div>"
htmlFile.WriteLine " <div>Contrast: <input type='range' class='slider'
min='0' max='200' value='100' onchange='adjustContrast(this.value)'></div>"
htmlFile.WriteLine " </div>"
htmlFile.WriteLine " <div id='overlay' onclick='closeImage()'>"
htmlFile.WriteLine " <img id='enlargedImg'>"
htmlFile.WriteLine " </div>"
End Sub
Sub WriteFooter(htmlFile)
htmlFile.WriteLine "<script>"
htmlFile.WriteLine " let currentBrightness = 100;"
htmlFile.WriteLine " let currentContrast = 100;"
htmlFile.WriteLine " function showAllImages() {"
htmlFile.WriteLine " document.querySelectorAll('.image-box
img').forEach(img => {"
htmlFile.WriteLine " img.style.display = 'block';"
htmlFile.WriteLine " });"
htmlFile.WriteLine " }"
htmlFile.WriteLine " function resetImages() {"
htmlFile.WriteLine " document.querySelectorAll('.image-box
img').forEach(img => {"
htmlFile.WriteLine " img.style.filter = 'brightness(100%)
contrast(100%)';"
htmlFile.WriteLine " });"
htmlFile.WriteLine " document.querySelectorAll('.slider').forEach(slider
=> {"
htmlFile.WriteLine " slider.value = 100;"
htmlFile.WriteLine " });"
htmlFile.WriteLine " currentBrightness = 100;"
htmlFile.WriteLine " currentContrast = 100;"
htmlFile.WriteLine " }"
htmlFile.WriteLine " function enlargeImage(img) {"
htmlFile.WriteLine " const overlay =
document.getElementById('overlay');"
htmlFile.WriteLine " const enlargedImg =
document.getElementById('enlargedImg');"
htmlFile.WriteLine " enlargedImg.src = img.src;"
htmlFile.WriteLine " enlargedImg.style.filter = img.style.filter;"
htmlFile.WriteLine " overlay.style.display = 'block';"
htmlFile.WriteLine " }"
htmlFile.WriteLine " function closeImage() {"
htmlFile.WriteLine " document.getElementById('overlay').style.display =
'none';"
htmlFile.WriteLine " }"
htmlFile.WriteLine " function adjustBrightness(value) {"
htmlFile.WriteLine " currentBrightness = value;"
htmlFile.WriteLine " updateImageFilters();"
htmlFile.WriteLine " }"
htmlFile.WriteLine " function adjustContrast(value) {"
htmlFile.WriteLine " currentContrast = value;"
htmlFile.WriteLine " updateImageFilters();"
htmlFile.WriteLine " }"
htmlFile.WriteLine " function updateImageFilters() {"
htmlFile.WriteLine " const filter = 'brightness(' + currentBrightness +
'%) contrast(' + currentContrast + '%)';"
htmlFile.WriteLine " document.querySelectorAll('.image-box
img').forEach(img => {"
htmlFile.WriteLine " img.style.filter = filter;"
htmlFile.WriteLine " });"
htmlFile.WriteLine " }"
htmlFile.WriteLine " function handleImageError(img) {"
htmlFile.WriteLine " img.parentElement.style.display = 'none';"
htmlFile.WriteLine " }"
' Add these lines to WriteFooter before the closing script tag
htmlFile.WriteLine " function toggleDisputeComment(id) {"
htmlFile.WriteLine " const commentDiv =
document.getElementById('dispute-comment-' + id);"
htmlFile.WriteLine " const checkbox = document.getElementById('dispute-
check-' + id);"
htmlFile.WriteLine " commentDiv.style.display = checkbox.checked ?
'block' : 'none';"
htmlFile.WriteLine " }"
' Updated saveDispute function to save comment directly into HTML (in browser
view) AND update summary
htmlFile.WriteLine " function saveDispute(id) {"
htmlFile.WriteLine " const commentBox =
document.getElementById('comment-' + id);"
htmlFile.WriteLine " const comment = commentBox.value.trim();"
htmlFile.WriteLine " if (comment === '') {"
htmlFile.WriteLine " alert('Please enter a comment before
saving.');"
htmlFile.WriteLine " return;"
htmlFile.WriteLine " }"
htmlFile.WriteLine " const parent = document.getElementById('dispute-
comment-' + id);"
htmlFile.WriteLine " const savedDiv = document.createElement('div');"
htmlFile.WriteLine " savedDiv.className = 'saved-comment-content';"
htmlFile.WriteLine " savedDiv.innerHTML = '<strong>Saved
Comment:</strong><br>' + comment;"
htmlFile.WriteLine " parent.innerHTML = '';"
htmlFile.WriteLine " parent.appendChild(savedDiv);"
' Add comment to the summary section at the top
htmlFile.WriteLine " const summaryDiv =
document.getElementById('dispute-summary');"
' Show the summary section if it's hidden
htmlFile.WriteLine " summaryDiv.style.display = 'block';"
' Check if the summary needs a header - using querySelector to check for
existing h3
htmlFile.WriteLine " if (!summaryDiv.querySelector('h3')) {"
htmlFile.WriteLine " const header = document.createElement('h3');"
htmlFile.WriteLine " header.textContent = 'Disputable Defects Emails
Summary';"
htmlFile.WriteLine " summaryDiv.appendChild(header);"
htmlFile.WriteLine " }"
' Create and append the comment entry
htmlFile.WriteLine " const commentEntry = document.createElement('p');"
htmlFile.WriteLine " commentEntry.innerHTML = '<strong>Email #' + id +
':</strong> ' + comment;"
htmlFile.WriteLine " summaryDiv.appendChild(commentEntry);"
htmlFile.WriteLine " }"
htmlFile.WriteLine "</script>"
htmlFile.WriteLine "</body>"
htmlFile.WriteLine "</html>"
End Sub