I don't recall making any changes to the code, but now my helper function for sending emails gets the following error:
com_error: (-2147352567, 'Exception occurred.', (4096, 'Microsoft Outlook', 'The operation failed.', None, 0, -2147467259), None)
The error happens at the GetInspector line of my function:
Cell In[78], line 9
7 msg = outlook.CreateItem(0)
8 msg.HTMLBody = ''
----> 9 msg.GetInspector.WordEditor.Range(Start=0, End=0).Paste()
File ~\AppData\Roaming\Python\Python310\site-packages\win32com\client\dynamic.py:620, in CDispatch.__getattr__(self, attr)
616 debug_attr_print(
617 "Getting property Id 0x%x from OLE object" % retEntry.dispid
618 )
619 try:
--> 620 ret = self._oleobj_.Invoke(retEntry.dispid, 0, invoke_type, 1)
621 except pythoncom.com_error as details:
622 if details.hresult in ERRORS_BAD_CONTEXT:
623 # May be a method.
Code:
import win32com.client
path = 'C:\\Documents\\'
filename = 'Book1.xlsx'
excel = win32com.client.gencache.EnsureDispatch('Excel.Application')
def send_email(path, filename):
book = excel.Workbooks.Open(path+filename)
book.Sheets(1).Range("A1:B2").Copy()
outlook = win32com.client.Dispatch("Outlook.Application")
msg = outlook.CreateItem(0)
msg.HTMLBody = ''
### msg.Display
msg.GetInspector.WordEditor.Range(Start=0, End=0).Paste()
msg.To = 'myemail@outlook.com'
msg.Send
send_email(path,filename)
If I display the mail item (commented out), paste from clipboard and press send myself, everything else works.
Sample Table (copy paste to range A1:B2)
| Column A | Column B |
|---|---|
| Cell 1 | Cell 2 |
| Cell 3 | Cell 4 |
Ideally, the pasted table in Outlook should retain excel formatting.
You can paste an Excel range into the body of an Outlook email using win32com.client without hitting the GetInspector error by considering the following:
Use msg.Display() before accessing WordEditor.
Avoid sending before Outlook fully loads the email item.
Optionally add a short delay to ensure the COM object is ready.
Here's a working version of your code. I've already tested it and it works.
import time
import win32com.client as win32
excel = win32.gencache.EnsureDispatch('Excel.Application')
def send_email(path, filename):
# Open workbook and copy range
book = excel.Workbooks.Open(path + filename)
book.Sheets(1).Range("A1:B3").Copy()
# Create Outlook email
outlook = win32.Dispatch("Outlook.Application")
msg = outlook.CreateItem(0)
msg.HTMLBody = 'Hi There'
# Display the email first (important for WordEditor to be available)
msg.Display()
time.sleep(0.5) # Small delay for COM to be ready
# Paste the copied Excel range
msg.GetInspector.WordEditor.Range(Start=0, End=0).Paste()
# Email details
msg.To = "myemail@outlook.com"
msg.Subject = "Excel Data"
msg.BodyFormat = 2 # 2 = HTML format
# Send the email
msg.Send()
# Close the Excel workbook
book.Close(SaveChanges=False)
path = r"D:\\"
filename = "Book1.xlsx"
# Update these to match your local Excel file
send_email(path, filename )
Why this fixes the error:
msg.Display() before WordEditor
GetInspector.WordEditor only works after the email window is displayed or fully initialized.Small delay (time.sleep)
One more thing, In your code, you’re calling msg.Send without parentheses (msg.Send() is needed).
here's a more optimised version of your code.