I have VBA code, in a rule, that saves emails as individual text files as they arrive.
The problem is that text within the .txt files begins to wrap at a certain distance down the .txt file, eventually becoming a single character per row.
This does not happen if I open the email individually, and then use the File>Save As command to save it as a .txt file (no wrapping at all).
As far as I can tell, this may be happening because the rule runs automatically and does not open the email first.
Is there a way to save the text file without text wrapping?
Alternately, I think a solution would be a macro to:
Open email on screen when it is received
Save the email as a .txt file
Close the email on screen
The current macro (taken from Slipstick I think):
Sub ExportEmailBodyToTXT(myMail As Outlook.MailItem)
Dim strFolder As String
Dim strSubject As String
Dim strFile As String
'Change the path to the specific Windows folder
strFolder = "C:\Users\madmanmick\Desktop\Folder_X"
If myMail.Subject <> "" Then
'Remove unsupported characters in subject
strSubject = myMail.Subject
strSubject = Replace(strSubject, "/", " ")
strSubject = Replace(strSubject, "\", " ")
strSubject = Replace(strSubject, ":", "")
strSubject = Replace(strSubject, "?", " ")
strSubject = Replace(strSubject, Chr(34), " ")
strdate = Format(myMail.ReceivedTime, "yyyy mm dd ")
strFile = strFolder & "\" & strdate & myMail.Subject & ".txt"
myMail.SaveAs strFile, OLTXT
End If
End Sub
Related
I used below code to save outlook emails in folders and subfolder to local drive and preserve original directory.
Private objFileSystem As Object
Private Sub ExportFolderWithAllItems()
Dim objFolder As Outlook.Folder
Dim strPath As String
'Specify the local folder where to save the emails
strPath = "C:\Users\qiaoqiao\"
Set objFileSystem = CreateObject("Scripting.FileSystemObject")
'Select a Outlook PST file or Outlook folder
Set objFolder = Outlook.Application.Session.PickFolder
Call ProcessFolders(objFolder, strPath)
MsgBox "Email saving is completed", vbExclamation
End Sub
Private Sub ProcessFolders(objCurrentFolder As Outlook.Folder, strCurrentPath As String)
Dim objItem As Object
Dim strSubject, strFileName, strFilePath As String
Dim objSubfolder As Outlook.Folder
'Create local folder based on Outlook mailbox folder directory
strCurrentPath = strCurrentPath & ModifyName(objCurrentFolder.Name)
objFileSystem.CreateFolder strCurrentPath
For Each objItem In objCurrentFolder.Items
strSubject = ModifyName(objItem.Subject)
strFileName = strSubject & ".msg"
strFilePath = strCurrentPath & "\" & strFileName
i = 0
Do Until False
strFilePath = strCurrentPath & "\" & strFileName
'Check if there exist emails with the same subject
If objFileSystem.FileExists(strFilePath) Then
'Add order number to the end of the subject
i = i + 1
strFileName = strSubject & " (" & i & ").msg"
Else
Exit Do
End If
Loop
'Save as MSG file
'On Error Resume Next
'Debug.Print Len(strFilePath)
objItem.SaveAs strFilePath, olMSG
Next
'Process subfolders recursively
If objCurrentFolder.Folders.Count > 0 Then
For Each objSubfolder In objCurrentFolder.Folders
Call ProcessFolders(objSubfolder, strCurrentPath & "\")
Next
End If
End Sub
Function ModifyName(folderName As String) As String
'Dim folderName As String
'In order to save emails in the same directory as in Outlook,
'when creating the folders in local drive,
'the folder name must not contain some special characters
folderName = Replace(folderName, ":", "")
folderName = Replace(folderName, "|", "")
folderName = Replace(folderName, ",", "")
folderName = Replace(folderName, "'", "")
folderName = Replace(folderName, "(", "")
folderName = Replace(folderName, ")", "")
folderName = Replace(folderName, "~", "")
folderName = Replace(folderName, "*", "")
folderName = Replace(folderName, "?", "")
folderName = Replace(folderName, "/", "")
folderName = Replace(folderName, "\", "")
folderName = Replace(folderName, """", "")
folderName = Trim(folderName)
'folderName = Replace(folderName, Chr(34), "")
ModifyName = folderName
End Function
However, since there are many layers of folders, so the strFilePath become very long, and it gave me a runtime error saying Operation failed.
Can anyone please advise me how to solve this issue? thank you in advance!!!
In Office products there is a limit to the number of characters in the file path. This error message occurs when you save or open a file if the path to the file (including the file name) exceeds 218 characters. This limitation includes three characters representing the drive, the characters in folder names, the backslash character between folders, and the characters in the file name.
Make sure that the path to the file contains fewer than 219 characters. To do this, use one of the following methods:
Rename the file so that it has a shorter name.
Rename one or more folders that contain the file so that they have shorter names.
Move the file to a folder with a shorter path name.
Note that if you enter 255 characters in the File Name box in the
Save As dialog box, and click OK, you will receive the following error message:
The path you entered, "<path>", is too long. Enter a shorter path.
Also, if you attempt to save a file and the path exceeds 255 characters, you will receive the following error message:
The file could not be accessed. Try one of the following:
- Make sure the specified folder exists.
- Make sure the folder that contains the file is not read-only.
- Make sure the file name does not contain any of the following characters: < > ? [ ] : | *.
- Make sure the file/path name doesn't contain more than 218 characters.
I obtained the code from a tutorial online.
I tested it and updated variables specific to my local system.
There is a problem with the export.
Previously, I ran the code successfully.
All 128 items of the Outlook folder were obtained.
There are now 231 items in the Outlook folder.
The code repeatedly only obtains 162.
I can confirm;
all items are mail (not meeting or read receipts)
the 162 items obtained contains attachments - so it is not a limit on this basis
I refreshed and sync'd Outlook exchange with local machine several times.
previously, one mail item contained *** in the title. This broke the code, I adapted it as can be seen, and it ran without issue.
I considered
mail items are of a type that I have not defined?
there is an issue with the titles of the other mail items?
this code is limited by memory allocation?
the problem is the sync between Outlook exchange and local device
Sub ZipAllEmailsInAFolder()
Dim objFolder As Outlook.Folder
Dim objItem As Object
Dim objMail As Outlook.MailItem
Dim strSubject As String
Dim varTempFolder As Variant
Dim varZipFile As Variant
Dim objShell As Object
Dim objFileSystem As Object
'Select an Outlook Folder
Set objFolder = Outlook.Application.Session.PickFolder
If Not (objFolder Is Nothing) Then
'Create a temp folder
varTempFolder = "C:\Users\thomdenm\Music\" & objFolder.Name & Format(Now, "YYMMDDHHMMSS")
MkDir (varTempFolder)
varTempFolder = varTempFolder & "\"
'Save each email as msg file
For Each objItem In objFolder.Items
If TypeOf objItem Is MailItem Then
Set objMail = objItem
strSubject = objMail.Subject
strSubject = Replace(strSubject, "/", " ")
strSubject = Replace(strSubject, "\", " ")
strSubject = Replace(strSubject, ":", "")
strSubject = Replace(strSubject, "?", " ")
strSubject = Replace(strSubject, Chr(34), " ")
strSubject = Replace(strSubject, "*", " ")
objMail.SaveAs varTempFolder & strSubject & ".msg", olMSG
End If
Next
'Create a new ZIP file
varZipFile = "C:\Users\thomdenm\Music\" & objFolder.Name & " Emails.zip"
Open varZipFile For Output As #1
Print #1, Chr$(80) & Chr$(75) & Chr$(5) & Chr$(6) & String(18, 0)
Close #1
'Add the exported msg files to the ZIP file
Set objShell = CreateObject("Shell.Application")
objShell.NameSpace(varZipFile).CopyHere objShell.NameSpace(varTempFolder).Items
On Error Resume Next
Do Until objShell.NameSpace(varZipFile).Items.Count = objShell.NameSpace(varTempFolder).Items.Count
Application.Wait (Now + TimeValue("0:00:01"))
Loop
On Error GoTo 0
'Delete the temp folder
Set objFileSystem = CreateObject("Scripting.FileSystemObject")
objFileSystem.DeleteFolder Left(varTempFolder, Len(varTempFolder) - 1)
End If
End Sub
First of all, I'd remove the condition where you check for the item type or add others to make sure all items are processed. Or just add a counter to see how much items were checked through.
counter = counter+1
If TypeOf objItem Is MailItem Then
Second, the On Error statement can help you identify the source of the problem if any error comes in.
Third, it makes sense to split the logic where you get Outlook items and save them to a folder. The other piece of code can be extracted to a separate method , so following this way you can easily be sure that one or another method works correctly (the Outlook-related part).
And, finally, the most important thing is that items can belong to the same conversation and have identical subject line which can lead to overwriting saved items in the folder. Is this the case?
objMail.SaveAs varTempFolder & strSubject & ".msg", olMSG
I'd recommend adding any ID to the file name so you can be sure no items are overwritten in the folder. For example, it can be current time or milliseconds and etc.
I want to add attachments from a specific folder. I specified the file's path and two keywords which are fixed.
There are more characters to complete the file path after 'filename2' and before 'pmonth' which are not fixed and hence I need to use wildcard (*).
The code gives
'Couldn't find file'
I have gone through various threads and tried solutions. None works for what I want.
For ctr = 2 To lastrow
filename1 = Cells(ctr, 1).Value
filename2 = Cells(ctr, 3).Value
Set OutMail = OutApp.CreateItemFromTemplate(str_template)
path = "C:\Users\nikunj.v.tripathi\Desktop\" & filename1 & "_" & filename2 & " -" & "*" & pmonth & " " & syear & ".xlsx"
With OutMail
.Attachments.Add path ' <----- this line gives error
.To = Cells(ctr, 10).Value
.cc = Cells(ctr, 11).Value
.htmlbody = Replace(.htmlbody, "#Month#", smonth)
.htmlbody = Replace(.htmlbody, "#CLIENT NAME#", Cells(ctr, 1).Value
.Save
End With
Next ctr
To use the Dir function effectively in this case, you'll need the path and the file name as two separate variables. Assuming you add another variable called filename, you could then utilise the following code...
...
path = "C:\Users\nikunj.v.tripathi\Desktop\"
filename = filename1 & "_" & filename2 & " -" & "*" & pmonth & " " & syear & ".xlsx"
...
filename = Dir(path & filename) ' Dir returns the filename of the first file matching
' the criteria, or returns an empty string if no match.
Do Until filename = ""
.Attachments.Add path & filename
filename = Dir ' Using Dir again returns the next file matching
' the criteria, or returns an empty string if no match.
Loop
Of course - Attachments.Add adds a single attachment and returns the Attachment object. How can it possibly add multiple attachments?
You can use Scripting.FileSystemObject to loop through all files in a folder and add one attachment at a time. See, for example
https://devblogs.microsoft.com/scripting/how-can-i-get-a-list-of-all-the-files-in-a-folder-and-its-subfolders/
Not sure why this is failing with a
"runtime error operation failed"
It seems to be crashing on the ".Attachments.Add fileName" line. I've read that you can run into issues if you are passing an object to the attachments, but I don't think I've done that.
Public Sub DraftEmailWithAttachment(strTo As String, strSubject As String, _
strBody As String, fileName As String)
Dim oApp As Object
Dim oEmail As Object
Set oApp = CreateObject("Outlook.Application")
Set oEmail = oApp.CreateItem(0)
With oEmail
.To = strTo
.subject = strSubject
.Attachments.Add fileName
.display
.HTMLBody = strBody & oEmail.HTMLBody
End With
End Sub
and
Private Sub btnEmailActionItems_Click()
Dim fileName As String
Dim todayDate As String
Dim strTo As String
Dim strSubject As String
Dim strBody As String
Dim filter As String
Dim oApp As Object
Dim oEmail As Object
Set oApp = CreateObject("Outlook.Application")
Set oEmail = oApp.CreateItem(0)
strTo = Nz(Me.cboUnderwriter.Column(2), "")
strSubject = Nz(Me.txtNamedInsured.Value, "") & " - " & _
Nz(Me.txtSubmissionNumber.Value, "") & " - " & _
Nz(Me.txtQuoteNumber.Value, "")
strBody = "Hello " & Me.cboUnderwriter.Column(3) & ", <br/><br/>"
todayDate = Format(Date, "MM.DD.YYYY")
fileName = "C:\Users\crewsj3\Desktop\tmp\Action Items Report -" & _
strSubject & " " & todayDate & ".pdf\"
filter = "submission_number=" & Nz(Me.txtSubmissionNumber.Value, "")
'generate filtered report
Call ExportFilteredReportToPDF("rptActionItemsForAllPolicies", fileName, filter)
'generate email
Call DraftEmailWithAttachment(strTo, strSubject, strBody, fileName)
End Sub
Any ideas?
Edit:
It looks like the problem was the trailing slash. works fine now. Thanks for the help.
The source of the attachment can be a file (represented by the full file system path with a file name) or an Outlook item that constitutes the attachment. See Attachments.Add for more information.
Based on the code listed above you just need to make sure the file path is valid and doesn't contain forbidden symbols. Try to copy the actual file path at runtime and paste it into any windows explorer window. Following that way, you can be sure that a file can be found and read.
Saving a file attachment in an Outlook mail item with the VBA method Attachment.SaveAsFile() call produces the expected result (file saved with same filename on the filesystem), even for file names with non-ASCII characters.
However, VBA apparently stores the file name in a 16-bit composite format String where accented letters are stored as a (letter, accent) pair. I can't find a way to output the string inside the message body with accented letters showing up as one glyph ("é") instead of two ("e´").
Concretely, the attachment is properly saved under the correct file name on disk when using the following code:
' Save the Outlook attachment
oAttachment.SaveAsFile (sTempFileLocation)
This results in a file being written to the folder specified in sTempFileLocation and the file name complies with the way it appears in the Outlook message (accents, non-ASCII characters etc).
However, when retrieving and manipulating the file name, it appears that a 16-bit composite internal representation of special characters is used. This means that the file name "à présent.txt" is displayed as "a` pre´sent.txt" (accented characters are represented with the character + the accent in 2 consecutive bytes).
For instance:
sAttachmentName = fso.getfilename(sTempFileLocation)
Debug.Print ("Attachment name = [" & sAttachmentName & "]")
will result in:
Attachment name = [a` pre´sent.txt]
There is little information available on this matter, all I found so far was this MSDN link describing the MultiByteToWideChar() function. From there it appears that the 16-bit internal VBA rendering happens implcitly and is even computer dependent (depending on code page and locale in use).
Here follows a self-contained minimalistic example that tries to save the email attachments of the first selected message to your My Documents folder unless it already exists:
Sub SaveMessageAttachments()
Dim objApp As Outlook.Application
Dim oSelection As Outlook.Selection
Dim aMail As Outlook.MailItem
Dim fso As Object
On Error Resume Next
' Instantiate an Outlook Application object.
Set objApp = CreateObject("Outlook.Application")
' Get the collection of selected objects.
Set oSelection = objApp.ActiveExplorer.Selection
If oSelection Is Nothing Then
Exit Sub
End If
' Select the 1st mail item in the current selection
Set aMail = oSelection.item(1)
Dim sAttachmentFolder As String
' Get the path to your "My Documents" folder
sAttachmentFolder = CreateObject("WScript.Shell").SpecialFolders(16)
Set fso = CreateObject("Scripting.FileSystemObject")
Dim oAttachments As Outlook.Attachments
Dim lItemAttachmentCount As Long
Set oAttachments = aMail.Attachments
lItemAttachmentCount = oAttachments.Count
If (lItemAttachmentCount > 0) Then
Dim lAttachmentIndex As Long
For lAttachmentIndex = 1 To lItemAttachmentCount
Dim oAttachment As Outlook.attachment
Set oAttachment = oAttachments.item(lAttachmentIndex)
Dim sFileName As String
sFileName = oAttachment.FileName
If LenB(sFileName) > 0 Then
Dim sFilePath As String
sFilePath = sAttachmentFolder & "\" & sFileName
If fso.fileexists(sFilePath) Then
MsgBox "Cannot save attachment " & lAttachmentIndex & vbCr _
& "File already exists: " & vbCr _
& sFilePath, vbExclamation + vbOKOnly
Else
If MsgBox("Saving atachment " & lAttachmentIndex & "?" & vbCr _
& "Save location: " & vbCr & sFilePath, _
vbQuestion + vbOKCancel) = vbOK Then
' Save the attachment to the temporary folder
oAttachment.SaveAsFile (sFilePath)
Dim sAttachmentName As String
sAttachmentName = fso.getfilename(sFilePath)
Dim lAttachmentLength As Long
lAttachmentLength = fso.getfile(sFilePath).size
Dim sURL As String
sURL = "file://" & Replace(sFilePath, "\", "/")
MsgBox "Attachment " & lAttachmentIndex _
& " saved as: " & sAttachmentName & vbCr _
& "Size: " & lAttachmentLength & vbCr _
& "URL = " & sURL, _
vbInformation + vbOKOnly
End If
End If
End If
Next lAttachmentIndex
End If
End Sub
As you will see, the SaveMessageAttachments() subroutine correctly saves the file to the filesystem, with the proper file name. However, Outlook dialogs (as well as when trying to write the attachment file name or URL to the message body in VBA) will always render the file names having accents differently. Please give it a try with an Outlook message having an attachment named e.g. "à présent.txt").
What is strange, however, is that if I try to paste sURL in the message body, although the URL is incorrectly written (2 character decomposition of accented letters) Outlook seems to find and open the file.
How can I transform this accented string (sAttachmentName) with VBA in order to correctly paste it ("à présent.txt" instead of "a` pre´sent.txt") into the message body?