问题
I am working on a project that requires me to save large numbers of attachments to a folder and filter them.
I can currently save the attachments with the subject of the email as the filename. If there is more than 1 attachment then it saves as the subject line with a (1) or (2) and so on.
I currently have a script that will do most of what I need (Thanks to the help from 0m3r in the replys below)
The last thing I need to complete this script is something that will omit special caracters from the subject line before it uses the subject line as the file name. The problem I am running into is the program does not save files correctly if the subject is a Forward (FW:) or a Reply (RE:) I suspect the ":" is what is breaking the save file. For example if the Subject reads "FW: Here is the file you requested 2017" what I am getting is a file saved as "FW" without a file extensions. What I need is to remove the ":" or the "FW:" so this does not happen.
Can someone provide me with the correction I need to remove special characters from the subject as its converted to the save file name?
I think an Array will be needed to accomplish this but I am not sure how to implament it and what part of the script to add it into.
Something like Array("<", ">", "|", "/", "*", "\", "?", """", "'", ":")
Public Function SaveAttachmentsFromSelection() As Long
Dim objFSO As Object
Dim objShell As Object
Dim objFolder As Object
Dim objItem As Object
Dim selItems As Selection
Dim atmt As Attachment
Dim strAtmtPath As String
Dim strAtmtFullName As String
Dim strAtmtName As String
Dim strAtmtNameTemp As String
Dim intDotPosition As Integer
Dim atmts As Attachments
Dim lCountEachItem As Long
Dim lCountAllItems As Long
Dim strFolderPath As String
Dim blnIsEnd As Boolean
Dim blnIsSave As Boolean
blnIsEnd = False
blnIsSave = False
lCountAllItems = 0
On Error Resume Next
Set selItems = ActiveExplorer.Selection
If Err.Number = 0 Then
lHwnd = FindWindow(olAppCLSN, vbNullString)
If lHwnd <> 0 Then
Set objShell = CreateObject("Shell.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objShell.BrowseForFolder(lHwnd, "Select folder to save attachments:", _
BIF_RETURNONLYFSDIRS + BIF_DONTGOBELOWDOMAIN, CSIDL_DESKTOP)
If Err.Number <> 0 Then
MsgBox "Run-time error '" & CStr(Err.Number) & " (0x" & CStr(Hex(Err.Number)) & ")':" & vbNewLine & _
Err.Description & ".", vbCritical, "Error from Attachment Saver"
blnIsEnd = True
GoTo PROC_EXIT
End If
If objFolder Is Nothing Then
strFolderPath = ""
blnIsEnd = True
GoTo PROC_EXIT
Else
strFolderPath = CGPath(objFolder.Self.Path)
For Each objItem In selItems
lCountEachItem = objItem.Attachments.Count
If lCountEachItem > 0 Then
Set atmts = objItem.Attachments
For Each atmt In atmts
strAtmtFullName = atmt.FileName
intDotPosition = InStrRev(strAtmtFullName, ".")
strAtmtName = Right$(strAtmtFullName, Len(strAtmtFullName) - intDotPosition)
strAtmtPath = strFolderPath & objItem.subject & Chr(46) & strAtmtName
Dim lngF As Long
lngF = 1
If Len(strAtmtPath) <= MAX_PATH Then
blnIsSave = True
Do While objFSO.FileExists(strAtmtPath)
strAtmtNameTemp = objItem.subject & "(" & lngF & ")"
strAtmtPath = strFolderPath & strAtmtNameTemp & Chr(46) & strAtmtName
If Len(strAtmtPath) > MAX_PATH Then
lCountEachItem = lCountEachItem - 1
blnIsSave = False
Exit Do
End If
lngF = lngF + 1
Loop
If blnIsSave Then atmt.SaveAsFile strAtmtPath
Else
lCountEachItem = lCountEachItem - 1
End If
Next
End If
lCountAllItems = lCountAllItems + lCountEachItem
Next
End If
Else
MsgBox "Failed to get the handle of Outlook window!", vbCritical, "Error from Attachment Saver"
blnIsEnd = True
GoTo PROC_EXIT
End If
Else
MsgBox "Please select an Outlook item at least.", vbExclamation, "Message from Attachment Saver"
blnIsEnd = True
End If
PROC_EXIT:
SaveAttachmentsFromSelection = lCountAllItems
If Not (objFSO Is Nothing) Then Set objFSO = Nothing
If Not (objItem Is Nothing) Then Set objItem = Nothing
If Not (selItems Is Nothing) Then Set selItems = Nothing
If Not (atmt Is Nothing) Then Set atmt = Nothing
If Not (atmts Is Nothing) Then Set atmts = Nothing
If blnIsEnd Then End
End Function
Public Function CGPath(ByVal Path As String) As String
If Right(Path, 1) <> "\" Then Path = Path & "\"
CGPath = Path
End Function
Public Sub ExecuteSaving()
Dim lNum As Long
lNum = SaveAttachmentsFromSelection
If lNum > 0 Then
MsgBox CStr(lNum) & " attachment(s) was(were) saved successfully.", vbInformation, "Message from Attachment Saver"
Else
MsgBox "No attachment(s) in the selected Outlook items.", vbInformation, "Message from Attachment Saver"
End If
End Sub
回答1:
You need to modify your For Each loop
, Try this...
Change this
Dim strAtmtName(1) As String
To this
Dim strAtmtName As String
And then modify your For Each loop
like this
For Each Atmt In atmts
strAtmtFullName = Atmt.FileName
intDotPosition = InStrRev(strAtmtFullName, ".")
strAtmtName = Right$(strAtmtFullName, Len(strAtmtFullName) - intDotPosition)
strAtmtPath = strFolderPath & objItem.Subject & Chr(46) & strAtmtName
Dim lngF As Long
lngF = 1
If Len(strAtmtPath) <= MAX_PATH Then
blnIsSave = True
Do While objFSO.FileExists(strAtmtPath)
strAtmtNameTemp = objItem.Subject & "(" & lngF & ")"
strAtmtPath = strFolderPath & strAtmtNameTemp & Chr(46) & strAtmtName
If Len(strAtmtPath) > MAX_PATH Then
lCountEachItem = lCountEachItem - 1
blnIsSave = False
Exit Do
End If
lngF = lngF + 1
Loop
回答2:
After some digging aroung looking at several posible options for omiting special characters from the subject line and some toying aroung with the macro I have come up with what seams to work perfectly for what I need.
Thank you 0m3r for your inital assistance in getting this taken care of.
The code below:
- selcet the folder to save all attachments to.
- It then pulls the subject line of each email
- Replaces any special characters I define with "_"
- Saves the file as the modified subject line.
- Repeates process for every selected email.
Paste:
Public Function SaveAttachmentsFromSelection() As Long
Dim objFSO As Object
Dim objShell As Object
Dim objFolder As Object
Dim objItem As Outlook.MailItem
Dim selItems As Selection
Dim atmt As Attachment
Dim strAtmtPath As String
Dim strAtmtFullName As String
Dim strAtmtName As String
Dim strAtmtNameTemp As String
Dim intDotPosition As Integer
Dim atmts As Attachments
Dim lCountEachItem As Long
Dim lCountAllItems As Long
Dim strFolderPath As String
Dim blnIsEnd As Boolean
Dim blnIsSave As Boolean
Dim strPrompt As String, strname As String
Dim sreplace As String, mychar As Variant
blnIsEnd = False
blnIsSave = False
lCountAllItems = 0
On Error Resume Next
Set selItems = ActiveExplorer.Selection
If Err.Number = 0 Then
lHwnd = FindWindow(olAppCLSN, vbNullString)
If lHwnd <> 0 Then
Set objShell = CreateObject("Shell.Application")
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set objFolder = objShell.BrowseForFolder(lHwnd, "Select folder to save attachments:", _
BIF_RETURNONLYFSDIRS + BIF_DONTGOBELOWDOMAIN, CSIDL_DESKTOP)
If Err.Number <> 0 Then
MsgBox "Run-time error '" & CStr(Err.Number) & " (0x" & CStr(Hex(Err.Number)) & ")':" & vbNewLine & _
Err.Description & ".", vbCritical, "Error from Attachment Saver"
blnIsEnd = True
GoTo PROC_EXIT
End If
If objFolder Is Nothing Then
strFolderPath = ""
blnIsEnd = True
GoTo PROC_EXIT
Else
strFolderPath = CGPath(objFolder.Self.Path)
For Each objItem In selItems
lCountEachItem = objItem.Attachments.Count
If lCountEachItem > 0 Then
Set atmts = objItem.Attachments
If objItem.Class = olMail Then
If objItem.subject <> vbNullString Then
strname = objItem.subject
Else
strname = "No_Subject"
End If
sreplace = "_"
For Each mychar In Array("/", "\", ":", "?", Chr(34), "<", ">", "¦")
'do the replacement for each character that's illegal
strname = Replace(strname, mychar, sreplace)
Next mychar
End If
For Each atmt In atmts
strAtmtFullName = atmt.FileName
intDotPosition = InStrRev(strAtmtFullName, ".")
strAtmtName = Right$(strAtmtFullName, Len(strAtmtFullName) - intDotPosition)
strAtmtPath = strFolderPath & strname & Chr(46) & strAtmtName
Dim lngF As Long
lngF = 1
If Len(strAtmtPath) <= MAX_PATH Then
blnIsSave = True
Do While objFSO.FileExists(strAtmtPath)
strAtmtNameTemp = strname & "(" & lngF & ")"
strAtmtPath = strFolderPath & strAtmtNameTemp & Chr(46) & strAtmtName
If Len(strAtmtPath) > MAX_PATH Then
lCountEachItem = lCountEachItem - 1
blnIsSave = False
Exit Do
End If
lngF = lngF + 1
Loop
If blnIsSave Then atmt.SaveAsFile strAtmtPath
Else
lCountEachItem = lCountEachItem - 1
End If
Next
End If
lCountAllItems = lCountAllItems + lCountEachItem
Next
End If
Else
MsgBox "Failed to get the handle of Outlook window!", vbCritical, "Error from Attachment Saver"
blnIsEnd = True
GoTo PROC_EXIT
End If
Else
MsgBox "Please select an Outlook item at least.", vbExclamation, "Message from Attachment Saver"
blnIsEnd = True
End If
PROC_EXIT:
SaveAttachmentsFromSelection = lCountAllItems
If Not (objFSO Is Nothing) Then Set objFSO = Nothing
If Not (objItem Is Nothing) Then Set objItem = Nothing
If Not (selItems Is Nothing) Then Set selItems = Nothing
If Not (atmt Is Nothing) Then Set atmt = Nothing
If Not (atmts Is Nothing) Then Set atmts = Nothing
If blnIsEnd Then End
End Function
Public Function CGPath(ByVal Path As String) As String
If Right(Path, 1) <> "\" Then Path = Path & "\"
CGPath = Path
End Function
Public Sub ExecuteSaving()
Dim lNum As Long
lNum = SaveAttachmentsFromSelection
If lNum > 0 Then
MsgBox CStr(lNum) & " attachment(s) was(were) saved successfully.", vbInformation, "Message from Attachment Saver"
Else
MsgBox "No attachment(s) in the selected Outlook items.", vbInformation, "Message from Attachment Saver"
End If
End Sub
Edit:
Section of script used for API declarations that are needed to make this script work in outlooks VBA. This section of code goes before you declare all your variables above the line Public Function SaveAttachmentsFromSelection() As Long
Option Explicit
' *****************
' For Outlook 2010.
' *****************
#If VBA7 Then
' The window handle of Outlook.
Private lHwnd As LongPtr
' /* API declarations. */
Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, _
ByVal lpWindowName As String) As LongPtr
' *****************************************
' For the previous version of Outlook 2010.
' *****************************************
#Else
' The window handle of Outlook.
Private lHwnd As Long
' /* API declarations. */
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, _
ByVal lpWindowName As String) As Long
#End If
' The class name of Outlook window.
Private Const olAppCLSN As String = "rctrl_renwnd32"
' Windows desktop - the virtual folder that is the root of the namespace.
Private Const CSIDL_DESKTOP = &H0
' Only return file system directories. If the user selects folders that are not part of the file system, the OK button is grayed.
Private Const BIF_RETURNONLYFSDIRS = &H1
' Do not include network folders below the domain level in the dialog box's tree view control.
Private Const BIF_DONTGOBELOWDOMAIN = &H2
' The maximum length for a path is 260 characters.
Private Const MAX_PATH = 260
来源:https://stackoverflow.com/questions/41989240/how-can-i-extract-attachments-from-outlook-save-as-subject-line-and-remove-inva