working with attachments in outlook

Get help with using AutoHotkey (v2 or newer) and its commands and hotkeys
mewho
Posts: 4
Joined: 25 Jan 2024, 07:27

working with attachments in outlook

25 Jan 2024, 07:36

Hi All Gurus!

I have been banging my head against the wall with this problem...maybe someone can help.

Lets say i receive an email with 4 pdf attachments. my issue is that i need to select one of the attachments and forward it to a specific address and then select the other 3 and forward them to a different address.

what i want to do is to have an ahk script to select one of the attachments, hit a hotkey and have it automatically forward to a specific address (the forwarding addresses do not change, they are always the same)
And then, select the other attachment/s hit a different hotkey and have them forwarded to a different address.
i am able to do this if the user saves the attachments to a folder on the desktop, but not from within outlook.

Alternately, i can drag the attachments only (not the entire email) to an outlook folder, and have an ahk script monitor the folder and forward whatever is dragged there to a specific address.
Can anyone help me with this? is this even possible?


Thanks!
User avatar
flyingDman
Posts: 2832
Joined: 29 Sep 2013, 19:01

Re: working with attachments in outlook

25 Jan 2024, 22:24

This is an example how that could work. It is basic as it assumes that the first file goes to recipient 1 (^F1), the second to recipient 2(^F2), etc. But you can customize this to your liking. The email is assumed to be open when launching the script. The files are saved to disk (I do not think they can be sent without first being saved; someone could prove me wrong on that). You obviously can delete the files when done.

Code: Select all

lst := []
tos := ["rcpnt1@gmail.com","rcpnt2@gmail.com","rcpnt3@gmail.com","rcpnt4@gmail.com"]
olApp := ComObjActive("Outlook.Application")
For olAttachment in olApp.ActiveWindow.CurrentItem.Attachments
	{
	olAttachment.SaveAsFile("e:\" olAttachment.FileName)
	lst.push("e:\" olAttachment.FileName)
	}

^F1::
^F2::
^F3::
^F4::
	{
	item := substr(A_ThisHotkey,3)
	ol := olApp.CreateItem(0)
	ol.To := tos[item]
	ol.Subject := "This is the subject"
	ol.Body := "Please see attached"
	ol.attachments.add(lst[item])
	ol.display
	}


14.3 & 1.3.7
mewho
Posts: 4
Joined: 25 Jan 2024, 07:27

Re: working with attachments in outlook

26 Jan 2024, 05:24

ok, this is neat but i have some questions...

1. its not always 4 attachments, it can be 2 or 10
2. it doesn't seem to find the files after they are saved
3. it may be that one attachment needs to go to the first recipient, but the remaining attachments need to go the the second recipient, is there a way to handle this?

thanks so much for the help!
User avatar
flyingDman
Posts: 2832
Joined: 29 Sep 2013, 19:01

Re: working with attachments in outlook

26 Jan 2024, 13:36

re 1:The script handles any number of attachments.
re 2:Make sure the path is accessible (I used e:\; chose your own)
re 3:The following will send the first attachment to rcpnt1 (^F1) and all the others to rcpnt2 (^F2). This assumes obviously that the order of the attachments remains the same every time a new email is received).

Code: Select all

lst := []
olApp := ComObjActive("Outlook.Application")
For olAttachment in olApp.ActiveWindow.CurrentItem.Attachments
	{
	olAttachment.SaveAsFile("e:\" olAttachment.FileName)
	lst.push("e:\" olAttachment.filename)
	}

^F1::
	{
	ol := olApp.CreateItem(0)
	ol.To := "rcpnt1@gmail.com"
	ol.Subject := "This is the subject"
	ol.Body := "Please see attached"
	ol.attachments.add(lst[1])
	ol.display
	}

^F2::
	{
	ol := olApp.CreateItem(0)
	ol.To := "rcpnt2@gmail.com"
	ol.Subject := "This is the subject"
	ol.Body := "Please see attached"
	for x,y in lst
		if x > 1
			ol.Attachments.Add(lst[x])
	ol.display
	}
14.3 & 1.3.7
User avatar
Datapoint
Posts: 302
Joined: 18 Mar 2018, 17:06

Re: working with attachments in outlook

26 Jan 2024, 19:42

I may have gone a bit off-topic here. I added a GUI to pick which attachments go where.

To avoid having to save the attachments to disk it forwards the original email twice. Once to each recipient. It removes any attachments that were not selected. It also removes the original body and subject of the email.

The hotkey is Ctrl+F1.

Code: Select all

#Requires AutoHotkey v2
#SingleInstance Force

email1 := "someperson@xyz.com"
email2 := "anotherperson@xyz.com"

^F1::OutlookForwardAttachments()

OutlookForwardAttachments() {
	if !oItem := OutlookGetMailItem() {
		MsgBox "MailItem not selected.", "OutlookForwardAttachments", 0x40
		return
	}
	if !oItem.Sent {
		MsgBox "MailItem has not been sent.", "OutlookForwardAttachments", 0x40
		return
	}
	if !oItem.Attachments.Count {
		MsgBox "MailItem does not have attachments.", "OutlookForwardAttachments", 0x40
		return
	}
	; Get a list of attachments.
	attList := []
	for oAtt in oItem.Attachments
		attList.Push(oAtt.FileName)
	; Make the Gui.
	g := Gui()
	g.OnEvent("Close", GuiClose)
	g.AddText("x10 y10", email1)
	g.AddListBox("x10 y+10 r10 w250 vLBEmail1", attList)
	g.AddButton("x+10 y50 w50 vButton1", "-->").OnEvent("Click", Button1Click)
	g.AddButton("y+10 w50 vButton2", "<--").OnEvent("Click", Button2Click)
	g.AddText("x+10 y10", email2)
	g.AddListBox("y+10 r10 w250 vLBEmail2")
	g.AddButton("x10 y+10 vSend", "Send").OnEvent("Click", SendEmails.Bind(oItem))
	g.Show()
}

SendEmails(oItem, GuiCtrlObj, Info) {
	g := GuiCtrlObj.Gui
	LB1 := g["LBEmail1"], LB2 := g["LBEmail2"]
	oNewMail1 := oItem.Forward()
	oNewMail1.Subject := "", oNewMail1.Body := ""
	oRecip := oNewMail1.Recipients.Add(email1), oRecip.Resolve
	oNewMail2 := oItem.Forward()
	oNewMail2.Subject := "", oNewMail2.Body := ""
	oRecip := oNewMail2.Recipients.Add(email2), oRecip.Resolve
	; Remove LB2 attachments from oNewMail1
	for i, attName in ControlGetItems(LB2.Hwnd) {
		for oAtt in oNewMail1.Attachments
			if oAtt.FileName = attName {
				oAtt.Delete()
				break
			}
	}
	; Remove LB1 attachments from oNewMail2
	for i, attName in ControlGetItems(LB1.Hwnd) {
		for oAtt in oNewMail2.Attachments
			if oAtt.FileName = attName {
				oAtt.Delete()
				break
			}
	}
	g.Destroy()
	oNewMail1.Display
	oNewMail2.Display
	;oNewMail1.Send
	;oNewMail2.Send
}

Button1Click(GuiCtrlObj, Info) {
	g := GuiCtrlObj.Gui
	LB1 := g["LBEmail1"], LB2 := g["LBEmail2"]
	if !LB1.Text
		return
	LB2.Add([LB1.Text]), LB1.Delete(LB1.Value)
}

Button2Click(GuiCtrlObj, Info) {
	g := GuiCtrlObj.Gui
	LB1 := g["LBEmail1"], LB2 := g["LBEmail2"]
	if !LB2.Text
		return
	LB1.Add([LB2.Text]), LB2.Delete(LB2.Value)
}

GuiClose(g) {
	g.Destroy()
}

; Returns a MailItem object selected in an Explorer or displayed in an Inspector.
; Returns 0 if a MailItem is not found.
OutlookGetMailItem() {
	static olExplorer := 34
	static olInspector := 35
	static olMail := 43

	oWin := ComObjActive("Outlook.Application").ActiveWindow
	if oWin.Class = olExplorer {
		if oWin.ActiveInlineResponse
			return oWin.ActiveInlineResponse
		oSel := oWin.Selection
		if oSel.Count > 0
			if oSel.Item(1).Class = olMail
				return oSel.Item(1)
	}
	else if oWin.Class = olInspector
	&& oWin.CurrentItem.Class = olMail
		return oWin.CurrentItem
	return 0
}
Change the emails at the top of the script. Also, to send the emails instead of displaying them comment out the .Display lines and un-comment the .Send ones:

Code: Select all

email1 := "someperson@xyz.com"
email2 := "anotherperson@xyz.com"
...
	oNewMail1.Display
	oNewMail2.Display
	;oNewMail1.Send
	;oNewMail2.Send
User avatar
FanaticGuru
Posts: 1907
Joined: 30 Sep 2013, 22:25

Re: working with attachments in outlook

26 Jan 2024, 21:10

flyingDman wrote:
25 Jan 2024, 22:24
The files are saved to disk (I do not think they can be sent without first being saved; someone could prove me wrong on that).

One option for copying attachments to a new email without saving the attachments to a file first is to forward the email.

Code: Select all

olApp := ComObjActive("Outlook.Application")
olEmail := olApp.ActiveExplorer.Selection[1]	; get selected email
olEmail := olEmail.Forward						; forward email
olEmail.Body := ''								; remove body
olEmail.Subject := SubStr(olEmail.Subject, 5)	; remove 'FW: ' from beginning of Subject

X := olEmail.Attachments.Count + 1
While --X										; remove embedded attachments
	If olEmail.Attachments[X].PropertyAccessor.GetProperty('http://schemas.microsoft.com/mapi/proptag/0x3712001F') ~= '@'
		olEmail.Attachments.Remove(X)

while olEmail.Attachments.Count > 1	; remove all Attachments after first
	olEmail.Attachments.Remove(2)

olEmail.Display

This forwards a selected email, then cleans up its subject, deletes the body, deletes all embedded attachments, and deletes all attachments except for the first.

The detecting of embedded attachments is useful for other purposes where you want to save all the attachments in the list without getting all the embedded images that might be in the body of the email.

FG

Edit: Realized since I am removing attachments I need to loop through them backwards to not mess up the index. Also, I am not 100% about the method of detecting if embedded in all environments. All embedded attachments I have tested have a '@' in that property.
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
mewho
Posts: 4
Joined: 25 Jan 2024, 07:27

Re: working with attachments in outlook

29 Jan 2024, 06:39

OMG, you guys are incredible!
mewho
Posts: 4
Joined: 25 Jan 2024, 07:27

Re: working with attachments in outlook

29 Jan 2024, 06:44

@Datapoint
You rock so hard!!!
this is incredible...is there a way to limit this to pdf attachments only (or attachments over a certain size) because its picking up the signature images and there is no way to remove them.

thanks soooooo much!!!
User avatar
Datapoint
Posts: 302
Joined: 18 Mar 2018, 17:06

Re: working with attachments in outlook

29 Jan 2024, 11:44

Try this. It will only send PDF attachments.
FanaticGuru's suggestion for how to remove embedded attachments would probably work for deleting the signature images too. However, the code below just looks for files that end in "pdf".

Code: Select all

#Requires AutoHotkey v2
#SingleInstance Force

email1 := "someperson@xyz.com"
email2 := "anotherperson@xyz.com"

^F1::OutlookForwardAttachments()

OutlookForwardAttachments() {
	if !oItem := OutlookGetMailItem() {
		MsgBox "MailItem not selected.", "OutlookForwardAttachments", 0x40
		return
	}
	if !oItem.Sent {
		MsgBox "MailItem has not been sent.", "OutlookForwardAttachments", 0x40
		return
	}
	if !oItem.Attachments.Count {
		MsgBox "MailItem does not have attachments.", "OutlookForwardAttachments", 0x40
		return
	}
	; Get a list of attachments.
	attList := []
	for oAtt in oItem.Attachments {
		; Only add PDF attachments to the list
		if SubStr(oAtt.FileName, -3) = "pdf"
			attList.Push(oAtt.FileName)
	}
	; Make the Gui.
	g := Gui()
	g.OnEvent("Close", GuiClose)
	g.AddText("x10 y10", email1)
	g.AddListBox("x10 y+10 r10 w250 vLBEmail1", attList)
	g.AddButton("x+10 y50 w50 vButton1", "-->").OnEvent("Click", Button1Click)
	g.AddButton("y+10 w50 vButton2", "<--").OnEvent("Click", Button2Click)
	g.AddText("x+10 y10", email2)
	g.AddListBox("y+10 r10 w250 vLBEmail2")
	g.AddButton("x10 y+10 vSend", "Send").OnEvent("Click", SendEmails.Bind(oItem))
	g.Show()
}

SendEmails(oItem, GuiCtrlObj, Info) {
	g := GuiCtrlObj.Gui
	LB1 := g["LBEmail1"], LB2 := g["LBEmail2"]
	oNewMail1 := oItem.Forward()
	oNewMail1.Subject := "", oNewMail1.Body := ""
	oRecip := oNewMail1.Recipients.Add(email1), oRecip.Resolve
	oNewMail2 := oItem.Forward()
	oNewMail2.Subject := "", oNewMail2.Body := ""
	oRecip := oNewMail2.Recipients.Add(email2), oRecip.Resolve
	; Remove files that are not PDF from the new mail items
	for i, oNewMail in [oNewMail1, oNewMail2] {
		x := oNewMail.Attachments.Count + 1
		while --x
			if SubStr(oNewMail.Attachments[x].FileName, -3) != "pdf"
				oNewMail.Attachments.Remove(x)
	}
	; Remove LB2 attachments from oNewMail1
	for i, attName in ControlGetItems(LB2.Hwnd) {
		for oAtt in oNewMail1.Attachments
			if oAtt.FileName = attName {
				oAtt.Delete()
				break
			}
	}
	; Remove LB1 attachments from oNewMail2
	for i, attName in ControlGetItems(LB1.Hwnd) {
		for oAtt in oNewMail2.Attachments
			if oAtt.FileName = attName {
				oAtt.Delete()
				break
			}
	}
	g.Destroy()
	oNewMail1.Display
	oNewMail2.Display
	;oNewMail1.Send
	;oNewMail2.Send
}

Button1Click(GuiCtrlObj, Info) {
	g := GuiCtrlObj.Gui
	LB1 := g["LBEmail1"], LB2 := g["LBEmail2"]
	if !LB1.Text
		return
	LB2.Add([LB1.Text]), LB1.Delete(LB1.Value)
}

Button2Click(GuiCtrlObj, Info) {
	g := GuiCtrlObj.Gui
	LB1 := g["LBEmail1"], LB2 := g["LBEmail2"]
	if !LB2.Text
		return
	LB1.Add([LB2.Text]), LB2.Delete(LB2.Value)
}

GuiClose(g) {
	g.Destroy()
}

; Returns a MailItem object selected in an Explorer or displayed in an Inspector.
; Returns 0 if a MailItem is not found.
OutlookGetMailItem() {
	static olExplorer := 34
	static olInspector := 35
	static olMail := 43

	oWin := ComObjActive("Outlook.Application").ActiveWindow
	if oWin.Class = olExplorer {
		if oWin.ActiveInlineResponse
			return oWin.ActiveInlineResponse
		oSel := oWin.Selection
		if oSel.Count > 0
			if oSel.Item(1).Class = olMail
				return oSel.Item(1)
	}
	else if oWin.Class = olInspector
	&& oWin.CurrentItem.Class = olMail
		return oWin.CurrentItem
	return 0
}
Last edited by Datapoint on 31 Jan 2024, 18:25, edited 3 times in total.
User avatar
FanaticGuru
Posts: 1907
Joined: 30 Sep 2013, 22:25

Re: working with attachments in outlook

30 Jan 2024, 18:02

Datapoint wrote:
29 Jan 2024, 11:44
FanaticGuru's suggestion for how to remove embedded attachments would probably work for deleting the signature images too. However, the code below just looks for files that end in "pdf".

If you need to work with image files that cannot be separated from embedded images by their extension, here is a AttachmentEmbedded function.

Code: Select all

olApp := ComObjActive("Outlook.Application")
olEmail := olApp.ActiveExplorer.Selection[1]	; get selected email

List := ''
For olAttachment in olEmail.Attachments
	If AttachmentEmbedded(olAttachment)
		List .= 'Body`t' olAttachment.DisplayName '`n'
	else
		List .= 'List`t' olAttachment.DisplayName '`n'

MsgBox List

AttachmentEmbedded(olAttachment)
{
	If olAttachment.PropertyAccessor.GetProperty('http://schemas.microsoft.com/mapi/proptag/0x3712001F') ~= '@'
		Return true
}
This loops through all the attachments in an email and reports whether the attachment is in the body or list.

It is only one if-statement. I have read that possibly more things need to be checked to be sure but, in my usage, this seems to do the job.

Embedded images are very common in signature blocks, which are actually attachments but typically these want to be ignored in most cases.

FG
Hotkey Help - Help Dialog for Currently Running AHK Scripts
AHK Startup - Consolidate Multiply AHK Scripts with one Tray Icon
Hotstring Manager - Create and Manage Hotstrings
[Class] WinHook - Create Window Shell Hooks and Window Event Hooks
User avatar
Datapoint
Posts: 302
Joined: 18 Mar 2018, 17:06

Re: working with attachments in outlook

31 Jan 2024, 15:45

FanaticGuru wrote:
26 Jan 2024, 21:10
Realized since I am removing attachments I need to loop through them backwards to not mess up the index.
I just realized I made the exact same mistake, even after I had read FanaticGuru's post. I corrected my script above. Specifically, this part:

Code: Select all

	; Remove files that are not PDF from the new mail items
	for i, oNewMail in [oNewMail1, oNewMail2] {
		x := oNewMail.Attachments.Count + 1
		while --x
			if SubStr(oNewMail.Attachments[x].FileName, -3) != "pdf"
				oNewMail.Attachments.Remove(x)
	}
	
	...

Return to “Ask for Help (v2)”

Who is online

Users browsing this forum: gekunfei and 64 guests