Adding attachment creates new MailItem in Outlook Inbox folder - python

I am working with an empty msg file created via Outlook once. The following code adds a attachment to an email (you can save it using msg.SaveAs(Path=save_path)).
import win32com.client
msg_path = r'C:\email.msg'
attachment_path = r'C:\specimen.pdf'
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
msg = outlook.OpenSharedItem(msg_path)
msg.Attachments.Add(Source=attachment_path)
Problem: the last line msg.Attachments.Add(Source=attachment_path) creates a new duplicate mail in inbox folder.
I found an old discussion of the problem here:
Adding attachment creates new MailItem in inbox folder.
Here are some citations from there:
OpenSharedItem always creates a temporary message and imports the
contents of the MSG file; it does not work directly with the specified
file.
The problem is that the message gets saved when you add an
attachment, but there is nothing you can do about that.
The important part is that OOM is not working with an MSG file -
once it is imported into a message in one of Outlook folders, the
original MSG file is out of the picture.
Are there any workarounds to prevent Outlook from creating a new message in Inbox folder? If not, how to make Outlook save it in Junk Email folder?
My goal is to modify the existing empty msg file: add a subject line and an attachment.

Answering my own question,
The idea is to create a new mail instead of modifying the existing one.
Here is the code:
outlook = win32com.client.Dispatch("Outlook.Application")
msg = outlook.CreateItem(0)
msg.Attachments.Add(Source=str(attachment_path))
msg.SaveAs(Path=save_path)

Related

How to save created Python win32com msg file without displaying the email in the GUI?

I am using Pywin32 and win32com to programmatically create and save Outlook MSG files. (These are emails that will only ever be saved and never be sent across smtp.) I am able to create and save the emails, but it only works when the display() method is used. This is problematic because it creates and opens the actual Outlook email in the GUI.
When I comment out the display() method, the email message save method just runs forever and yields zero in the debug console and the email is neither created or saved.
The appearance of the Outlook emails in the GUI is not desirable as I will later programmatically create thousands of messages and cannot have them all opening in the GUI. (and having to close them!)
edit: I've done some research here display method and here .net mail class but have not found a way to suppress the GUI display of the email.
How can I create the emails to disk as msg files without them appearing in the Windows GUI as Outlook emails? Code as follows. Thank you.
import sys
import win32com.client as client
MSG_FOLDER_PATH = "d:\\Emails_Msg\\"
html_body = """
<div>
Test email 123
</div><br>
"""
recipient = "johndoe#foo.com"
cc = "janedoe#foo.com"
outlook = client.Dispatch("outlook.application")
message = outlook.CreateItem(0)
message.To = recipient
message.CC = cc
message.Subject = "foo1"
message.HTMLBody = html_body
# message display method
message.Display()
# save the message, only works if message.Display() runs
message_name = MSG_FOLDER_PATH + "foo.msg"
message.SaveAs(message_name)
The problem was that Outlook was not opened in the Windows Server. (The simple things at times!) Once it is opened, the display method is no longer needed and emails are written directly to disk.

Refresh outlook inbox via python script

I'm trying to read emails from the outlook by means of win32com.
It's working well only if the email are displayed in outlook desktop application. But it could de something in the server, which could not been seen without manual outlook inbox refreshing. Is this any chance to update the outlook via command and get the latest emails from the server?
Currient code:
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
accounts= win32com.client.Dispatch("Outlook.Application").Session.Accounts;
inbox = outlook.Folders(accounts[0].DeliveryStore.DisplayName).Folders('Inbox')
Use Namespace.SendAndReceive - keep in mind that it is asynchronous, so you won't see the changes immediately.

Python win32com : Reading multiple Outlook inbox

I want to get the SenderEmailAddress of all email sent on two specified mail addresses : 123#abc.com and 456#def.com that are in my Outlook Application on my computer, the point is to make a list of all mail senders that will be kept in a csv file.
The architectures of these mailboxes are this way :
123#abc.com
-> Inbox
&
456#def.com
-> Inbox
I would like to read the Inbox Folders from the two mailboxes and store the SenderEmailAddress from the two Folders
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
I've found that for some people it works to use
inbox = outlook.GetDefaultFolder(6).Folders[1] # To access 123#abc.com Inbox
inbox = outlook.GetDefaultFolder(6).Folders[2] # To access 456#def.com Inbox
But in my case it just gets me inside of the two subfolders that are inside of Inbox and nothing more, I don't have the possibility to access at all to the second mailbox.
I have the possibility to detect these Mailboxes by using
for folder in outlook.Folders:
print(folder.Name)
I have no idea how to fix this and finally access to my second mail address, if anyone would be capable to help me on this it would be great.
Thanks !
That happens because GetDefaultFolder(6) is referencing to the first Inbox, thus .Folders[1] and .Folders[2] will only get you to the subfolders of that same first Inbox.
You can access those inboxes by specifying them like this:
inbox = outlook.Folders('123#abc.com').Folders('Inbox') # To access 123#abc.com Inbox
inbox = outlook.Folders('456#def.com').Folders('Inbox') # To access 456#def.com Inbox

Outlook / Python : Open specific message at screen

I want to do a "simple" task in Outlook, with a Python script, but I'm usually in PHP and it's a little bit difficult for me.
Here is the task:
Open Outlook (it's ok for that)
Check a specific account, example: test#test.com
Open the last mail
I want to open the "real" message windows at screen, not just to access to the content.
Is it possible?
For your second requirement, could the account be a shared inbox?
Here is the code for the rest:
import win32com.client
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
inbox = outlook.GetDefaultFolder(6)
messages = inbox.Items
message = messages.GetLast()
message.display()
Here is another example with exchangelib in python:
https://medium.com/#theamazingexposure/accessing-shared-mailbox-using-exchangelib-python-f020e71a96ab
Here is the snippet to get the last email. I did it using a combination of order by and picking the first one or the last one depending on how you order by:
from exchangelib import Credentials, Account, FileAttachment
credentials = Credentials('FirstName.LastName#Some_Domain.com', 'Your_Password_Here')
account = Account('FirstName.LastName#Some_Domain.com', credentials=credentials, autodiscover=True)
filtered_items = account.inbox.filter(subject__contains='Your Search String Here')
print("Getting latest email for given search string...")
for item in account.inbox.filter(subject__contains='Your Search String Here').order_by('-datetime_received')[:1]: #here is the order by clause:: you may use order_by('datetime_received')[:-1]
print(item.subject, item.text_body.encode('UTF-8'), item.sender, item.datetime_received) #item.text_body.encode('UTF-8') gives you the content of email
while trying to open the real message might be a bit of a challenge but I will update this section once I have a solution. If I may ask:: are you looking at a python only solution ?

Accessing Chat Folder in Python Using Imaplib

I am trying to access the Chat Folder using imaplib but am not able to do so. The code mail.select("Chats") doesn't work since "chats" is not actually a label.
How do I access the emails in the Chats folder?
any folder you want to access by imap. it should be allowed by mail server.
e.g : for gmail, check below image for, how to set access of imap.
here, "Show in IMAP" should be checked for "Chats" folder.
then after, try below code snippets:
sock = imaplib.IMAP4_SSL("imap.gmail.com", 993)
sock.login("your Email Id", "Password")
lb_list = sock.list() # print
#search for "Chats" folder and its signature
#here, it is "[Gmail]/Chats"
sock.select("[Gmail]/Chats", True)
sock.search(None, '(ALL)')
resp, data = sock.fetch('1:*', '(RFC822)')
Hope, it will be helpful.

Categories