根据发件人名称为附件创建文件夹

时间:2020-06-29 22:20:50

标签: vba outlook save attachment

学生通过电子邮件将评估答案发送给我,然后将其放在与评估编号相关的文件夹中。在完成评估时,可能会有多封来自该学生的电子邮件,它们带有不同的附件以供评估。

我的收件箱下有一个名为AllNZBAT的主文件夹。我有评估编号的子文件夹。 112、123、2785等用于学生的电子邮件。

我需要从多封电子邮件中提取学生的附件,然后将其放在文件夹中,并在该文件夹中添加学生姓名(发件人)以进行评估。

因此,文件夹“ John Smith”保留了所有他的附件以进行评估123。

我正在尝试编写执行此操作的宏。它创建文件夹树和带有学生姓名的文件夹。我找不到带有发件人姓名的文件夹中的附件。

有时候我会得到两个具有相同学生姓名的文件夹,但一个文件夹的名称后面还会有(Unicode编码冲突)。

Public Sub SaveAttachments()
Dim objOL As Outlook.Application
Dim objMsg As Outlook.MailItem 'Object
Dim objAttachments As Outlook.Attachments
Dim objSelection As Outlook.Selection
Dim i As Long
Dim lngCount As Long
Dim strFile As String
Dim strFolderpath As String
Dim strDeletedFiles As String
Dim myNewFolder As Outlook.Folder
Dim currentFolder As Outlook.Folder

'https://www.codeproject.com/Questions/5258321/Outlook-VBA-automatically-create-a-folder-based-on
'https://vbatutorialcode.com/save-all-attachments-from-outlook-into-folder-vba/
'https://stackoverflow.com/questions/15531093/save-attachments-to-a-folder-and-rename-them

Dim olApp As Outlook.Application
Dim objNS As Outlook.NameSpace
Dim olFolder As Outlook.MAPIFolder
Dim msg As Outlook.MailItem

Set olApp = Outlook.Application
Set objNS = olApp.GetNamespace("MAPI")
Set olFolder = objNS.GetDefaultFolder(olFolderInbox)
Set olFolder = olFolder.Folders("All NZBat")  'set the start folder - replace it with selection

' Instantiate an Outlook Application object.
Set objOL = CreateObject("Outlook.Application")

Dim FoldersArray As Variant
Dim LastFolder As Integer
Dim strParentFolderName As String

'use to create the folders on the drive
Dim fs As Object 'Using late binding to avoid having to include a reference to Microsoft Scripting Runtime
Set fs = CreateObject("Scripting.FileSystemObject")

'C:\Dropbox\NZBAT Resources\112FebStudetnResults
' Get the path to your My Documents folder
strFolderpath = CreateObject("WScript.Shell").SpecialFolders(16)

On Error Resume Next

'get all the folders under the All NZBat
For Each Folder In olFolder.Folders
  ' Debug.Print Folder.FolderPath    '\\*****@*****.ac.nz\Inbox\All NZBat\112
   
 Set currentFolder = Folder
     FoldersArray = Split(Folder.FolderPath, "\")
     LastFolder = UBound(FoldersArray)
     
     'Debug.Print FoldersArray(LastFolder) '112
     'get the last folder in the path string = 112 so we can make a new folder with its name
    strParentFolderName = FoldersArray(LastFolder)
    
'Next

'need to get all the emails in the folder

' Set the Attachment folder with the name of the sender.
strFolderpath = "C:\Dropbox\EmailedAssessments\" & strParentFolderName & "\"  ' & objMsg.SenderName & " \ "
 'Debug.Print strFolderpath  'C:\Dropbox\NZBAT Resources\112\
   '  strFolderpath = Replace(strFolderpath, " ", "_")
  'make the folder
    
    If Not fs.folderexists(strFolderpath) Then
        fs.createfolder (strFolderpath)
    End If



' Get the collection of selected objects.
Set objSelection = objOL.ActiveExplorer.Selection

'Set currentFolder = 'Application.ActiveExplorer.currentFolder

' Check each selected item for attachments. If attachments exist,
' save them to the strFolderPath folder and strip them from the item.
For Each objMsg In currentFolder.Items  'objSelection

'Debug.Print objMsg.Subject
strFolderpathFull = strFolderpath & objMsg.SenderName & " \ "
 ' strFolderpathFull = Replace(strFolderpathFull, " ", "_")
 
 'Debug.Print strFolderpathFull  'C:\Dropbox\NZBAT Resources\112\Kathryn Tonks \
 
 ' Dim fs As Object 'Using late binding to avoid having to include a reference to Microsoft Scripting Runtime
  '  Set fs = CreateObject("Scripting.FileSystemObject")
    
    'make the subfolder
    If Not fs.folderexists(strFolderpathFull) Then
        fs.createfolder (strFolderpathFull)
    End If

    ' This code only strips attachments from mail items.
    ' If objMsg.class=olMail Then
    ' Get the Attachments collection of the item.
    Set objAttachments = objMsg.Attachments
    lngCount = objAttachments.Count
    strDeletedFiles = ""

    If lngCount > 0 Then

        ' We need to use a count down loop for removing items
        ' from a collection. Otherwise, the loop counter gets
        ' confused and only every other item is removed.

        For i = lngCount To 1 Step -1

            ' Save attachment before deleting from item.
            ' Get the file name.
            strFile = objAttachments.Item(i).FileName

            ' Combine with the path to the Temp folder.& StudentFolder
            strFile = strFolderpathFull & strFile
       '    strFile = Replace(strFile, "_\_", "\")
         
 
            ' Save the attachment as a file.
            objAttachments.Item(i).SaveAsFile strFile
           Debug.Print strFile & " Saved attachment"


            'write the save as path to a string to add to the message
            'check for html and use html tags in link
            If objMsg.BodyFormat <> olFormatHTML Then
                strDeletedFiles = strDeletedFiles & vbCrLf & "<file://" & strFile & ">"
            Else
                strDeletedFiles = strDeletedFiles & "<br>" & "<a href='file://" & _
                strFile & "'>" & strFile & "</a>"
            End If

            'Use the MsgBox command to troubleshoot. Remove it from the final code.
            'MsgBox strDeletedFiles

        Next i

        ' Adds the filename string to the message body and save it
        ' Check for HTML body
        If objMsg.BodyFormat <> olFormatHTML Then
            objMsg.Body = vbCrLf & "The file(s) were saved to " & strDeletedFiles & vbCrLf & objMsg.Body
        Else
            objMsg.HTMLBody = "<p>" & "The file(s) were saved to " & strDeletedFiles & "</p>" & objMsg.HTMLBody
        End If
      
        
        g.Save
    End If
Next
Next
End Sub

1 个答案:

答案 0 :(得分:1)

您的代码确实可以工作了(顺便说一句,它不会以被复制到问题中的形式进行编译)...但是我没有完全调试它,而是采取了清理它直到工作的方法。有很多多余的代码。

下面的代码通过所有作业文件夹/学生文件夹和电子邮件信息读取...,创建作业子目录以及其中的学生目录,并将附件保存在作业/学生目录中。它将使用对已保存附件的引用来更新电子邮件正文。

如果您希望它仅适用于选定的文件夹,则需要对以下代码进行一些调整。

我怀疑目录名称重复的问题可能是由于来自学生电子邮件地址的不兼容字符被放入了学生的目录路径名中...所以我已经包含了一个非常原始的清理功能(我没有这样做)进行过多测试),以希望避免这种情况;它可能需要进行调整。

顺便说一句,我使用早期绑定,因此如果您还没有MS脚本运行时的引用,则需要添加它。

Option Explicit

Public Sub SaveAttachments()

    Const ParentDirectory = "C:\Dropbox\EmailedAssessments\"
    
    Dim fs As New FileSystemObject                          ' File system object
    Dim MAPINamspace As Outlook.NameSpace                   ' MAPI namespace
    Dim InboxFolder As folder                               ' Inbox
    Dim ParentFolder As folder                              ' Parent folder ... e.g. "ALL NZBAT"
    Dim AssignmentSubFolder As folder                       ' Assignment folders in Parent Folder
    Dim OutlookMessage As MailItem                          ' Outlook message
    Dim AssignmentDirectory As String                       ' Assignment Directory
    Dim StudentDirectory As String                          ' Student Directory (within Assignment Directory)
    Dim AttachmentPathFileName As String                    ' Attachment Path and File Name
    Dim DeletedAttachments As String                        ' A record of all deleted attachments to append to Outlook message
    Dim OutlookAttachment As Attachment                     ' Outlook attachment
    
    Set MAPINamspace = Outlook.Application.GetNamespace("MAPI")
    Set InboxFolder = MAPINamspace.GetDefaultFolder(olFolderInbox)
    Set ParentFolder = InboxFolder.Folders("ALL NZBAT")
    
    ' Get all the Outlook subfolders in the Parent Folder "ALL NZBAT"
    For Each AssignmentSubFolder In ParentFolder.Folders
        
        ' Setup the directory where each assignment's data will be saved
        AssignmentDirectory = ParentDirectory & AssignmentSubFolder.Name & "\"
        If Not fs.folderexists(AssignmentDirectory) Then
            fs.createfolder (AssignmentDirectory)
        End If
        
        ' Check each selected item for attachments. 
        For Each OutlookMessage In AssignmentSubFolder.Items
        
            ' Setup the directory where each student's attachments will be saved, cleaning (in a primitive way) the SenderName
            StudentDirectory = AssignmentDirectory & CleanName(OutlookMessage.SenderName) & "\"
            If Not fs.folderexists(StudentDirectory) Then
                fs.createfolder (StudentDirectory)
            End If
        
            ' Save all the attachments from the message
            DeletedAttachments = ""
            For Each OutlookAttachment In OutlookMessage.Attachments
                
                ' Save the attachment
                AttachmentPathFileName = StudentDirectory & OutlookAttachment.FileName
                OutlookAttachment.SaveAsFile AttachmentPathFileName
                
                ' Keep a record of the all the saved attachments.
                If OutlookMessage.BodyFormat <> olFormatHTML Then
                    DeletedAttachments = DeletedAttachments & vbCrLf & "<file://" & AttachmentPathFileName & ">"
                Else
                    DeletedAttachments = DeletedAttachments & "<br>" & "<a href='file://" & AttachmentPathFileName & "'>" & AttachmentPathFileName & "</a>"
                End If

            Next
        
            ' Append a record of all of the saved attachments to the start of the outlook message
            If DeletedAttachments <> "" Then
                If OutlookMessage.BodyFormat <> olFormatHTML Then
                    OutlookMessage.Body = vbCrLf & "The file(s) were saved to " & DeletedAttachments & vbCrLf & OutlookMessage.Body
                Else
                    OutlookMessage.HTMLBody = "<p>" & "The file(s) were saved to " & DeletedAttachments & "</p>" & OutlookMessage.HTMLBody
                End If
                OutlookMessage.Save
            End If
            
        Next
        
    Next
End Sub

Public Function CleanName(InputName As String) As String

    Dim Counter As Long
    Dim WorkChar As String
    
    ' A primitive file name cleaner
    For Counter = 1 To Len(InputName)
        WorkChar = Mid(InputName, Counter, 1)
        If Asc(WorkChar) <= 31 Or InStr(1, "<>:""/|?*", WorkChar) > 0 Then
            CleanName = CleanName & "_"
        Else
            CleanName = CleanName & WorkChar
        End If
    Next
    
End Function