I have an issue with embedded email images. Their borders come into the tkinter frame the right size and position as they do in Outlook, but only as broken links, and no image. Some images come in if they are fully html, like an email from mailchimp or similar news letter style, but a simple image placed inside the body of a normal email, or an image in an outlook signature, do not show.
I appreciate any help.
This is what I have so far:
import sys
import os
import tempfile
from PyQt6.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QWidget, QListWidget, QListWidgetItem, QDialog
from PyQt6.QtWebEngineWidgets import QWebEngineView
import win32com.client
from bs4 import BeautifulSoup
import base64
# Function to fetch emails from Outlook
def fetch_emails():
try:
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6) # 6 refers to the inbox folder
messages = inbox.Items
messages.Sort("[ReceivedTime]", True)
emails = []
for i in range(min(10, len(messages))): # Fetching last 10 emails
message = messages[i]
try:
# Check if HTMLBody is available and not empty
if hasattr(message, 'HTMLBody') and message.HTMLBody:
html_body = str(message.HTMLBody) # Convert HTMLBody to string
inline_images = save_inline_images(message)
html_body = replace_inline_images(html_body, inline_images)
emails.append({
'subject': message.Subject,
'html_body': html_body,
'datetime_received': message.ReceivedTime,
})
else:
emails.append({
'subject': message.Subject,
'html_body': '<p>This email does not contain HTML content.</p>',
'datetime_received': message.ReceivedTime,
})
print(f"Email {i} ('{message.Subject}') does not have an HTMLBody.")
except Exception as e:
print(f"An error occurred while accessing email {i} ('{message.Subject}'): {e}")
continue
return emails
except Exception as e:
print(f"An error occurred: {e}")
return []
# Function to save inline images from an email
def save_inline_images(message):
inline_images = {}
attachments = message.Attachments
for attachment in attachments:
if attachment.Type == 6: # Type 6 refers to inline images
cid = attachment.PropertyAccessor.GetProperty("http://schemas.microsoft.com/mapi/proptag/0x3712001F")
file_path = os.path.join(temp_dir, attachment.FileName)
attachment.SaveAsFile(file_path)
with open(file_path, "rb") as f:
image_data = f.read()
encoded_image = base64.b64encode(image_data).decode("utf-8")
inline_images[cid] = encoded_image
return inline_images
# Function to replace inline images in the HTML content
def replace_inline_images(html_body, inline_images):
soup = BeautifulSoup(html_body, 'html.parser')
for img in soup.find_all('img'):
src = img.get('src', '')
if src.startswith('cid:'):
cid = src[4:]
if cid in inline_images:
img['src'] = f"data:image/jpeg;base64,{inline_images[cid]}"
return str(soup)
class EmailViewer(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Outlook Email Viewer")
self.setGeometry(100, 100, 800, 600)
# Main layout
main_layout = QVBoxLayout()
main_widget = QWidget()
main_widget.setLayout(main_layout)
self.setCentralWidget(main_widget)
# Email list
self.email_list = QListWidget()
main_layout.addWidget(self.email_list)
# Fetch and display emails
self.emails = fetch_emails()
if not self.emails:
self.email_list.addItem(QListWidgetItem("No emails to display"))
for email in self.emails:
item = QListWidgetItem(f"{email['subject']} ({email['datetime_received']})")
self.email_list.addItem(item)
# Connect list item click to email display
self.email_list.itemClicked.connect(self.open_email_viewer)
def open_email_viewer(self, item):
index = self.email_list.row(item)
email = self.emails[index]
# Create a new window to display the email
self.email_window = QDialog(self)
self.email_window.setWindowTitle(email['subject'])
self.email_window.setGeometry(150, 150, 800, 600)
# Layout for the new window
email_layout = QVBoxLayout()
self.email_window.setLayout(email_layout)
# QWebEngineView to display the email content
email_viewer = QWebEngineView()
email_layout.addWidget(email_viewer)
email_viewer.setHtml(email['html_body'])
self.email_window.exec()
# Run the application
if __name__ == "__main__":
app = QApplication(sys.argv)
viewer = EmailViewer()
viewer.show()
sys.exit(app.exec())
I’ve tried so many different recommendations to fix this, but none of them seem to get the images to show up. Anything other than what I have, has so far only made it worse. The code I provided has been the closest to actually viewing an email like you can in Outlook. I have also noticed that emails that have no HTML just show up in this viewer with a note that says there is no html available.
Long story short, I just need to be able to view any/all emails as if they were opened in Outlook.
Joshua S is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.