Renaming attachments with content filter
-
Hello,
I've got an issue were someone is downloading messages, but if the attachment name is too long and contains too many spaces, it will trim off the extension. Is it possible to have a content filter rule (or some other process) that would replace the spaces with an "_" character before putting into the user's mailbox?
I can see text can be added or changed in the header and body sections, just not for the attachment section.
Thanks in advance.
-
Arron Staff
What email client is being used?
You'll probably have to use a script to do this. The actions in the content filter to change headers won't change the file attachment headers. And the actions to extract an attachment and add an attachment, but none to rename the attachment.
-
@Arron We are using Eudora Pro for Windows. I can go in manually and edit the message, replacing spaces with an "_" for example and it downloads OK. Something about the length of the attachment plus spaces causes a problem.
I tried using the attachment linking feature, but all that does it remove the attachment and give me a link, which fails to provide the attachment when clicked, so that's worthless as my searches on the server can't find the removed attachments. I thought it might give me the original attachment plus a link that could be used if the end user couldn't get the attachment, but it removes the attachment.
Max
-
Arron Staff
I have a powershell script that will save the attachment to disk, rename the file and then attach the new file to the email. It is not yet deleting the old attachment. It is probably more complicated than it needs to be, but most of it came from another script I had written. if you'd like a copy, let me know.
For attachment linking, If you go to Setup / Web & IM Servicese / Attachment linking, which options do you have selected?
If you are using the option to automatically manage the attachment linking settings, then the defualt location for storing attachments is used. The default location for storing attachments is MDaemon\Attachments\$DOMAIN$\$MAILBOX$\.
What attachment linking removes an attachment from an email, what is the URL that it is replaced with?
Is webmail available on the internet? Is webmail available to the client that wasn't able to download the file when the link was clicked?
Is a valid and trusted certificate being used in webmail?
-
@Arron That sounds interesting to try.
Here are the images from trying to use Attachment Linking. I have it set to be managed by Webmail. They can access Webmail on their computer.
Max
-
Response when link clicked.
-
Arron Staff
Does the message still exist in the mailbox?
Does the routing log show any errors when extracting the attachment?
Does the attachmentlinking.dat file still contain an entry for the file?
Does the al= value in the link match the value in the attachmentlinking.dat file?
Does the file still exist on disk in the path given in the attachmentlinking.dat file?
-
@Arron No, the file is not there. Routing log says it was successfully extracted. I think when it was pulled down to Eudora, it was removed from the inbox and that deletes the files. Nothing in attachmentlinking.dat.
-
Aaron,
Think that for attachment linking, the option to delete from the server when the message is deleted is turned on by default, I was able to test it with another account, turning that off and I could retrieve the attachment.
Would like to see the powershell option as I don't know if he wants to click the links everytime for something, but at least this might be a workaround.Max
-
Arron Staff
There is an option for attachment linking to delete the file when the message is deleted. If you are using POP3 to collect the message and have it configured to delete messagese from the server, then as soon as its downloaded the attachment will be removed from the server.
You can disable the option in MDaemon to delete attachments when the messages are deleted by going to Setup / Web & IM services / Attachment linking. If you do this, the attachments will never be removed from the server.
Or you could configure the POP3 clients to leave a copy of messages on the server for X days.
Or you could switch to IMAP.
-
Aaron,
Think that turning that delete option off will allow it to work. Would like to limit the attachments handled, but it has to be specific file names, no wild-cards. Or just from specific users, but it's all or nothing.
Is the Powershell program activated by using the content filter or some other process?
Max
-
Arron Staff
Here is a copy of the script I wrote. Its more complicated than it probably needs to be but I opted to extract the attachment and re-add it because I already had a script that was doing something similar.
The script is not deleting the original attachment, partially because I wasn't able to get it to work like I wanted, and partially because I thought it was a good means of testing it.
To use the script, you'll want to create a content filter rule with whatever conditions work for you, and that use the Run a process action. It should look something like the following:
RuleName=Rename Attachments
Enable=Yes
ThisRuleCondition=All
ProcessQueue=BOTH
Condition01=body|has attachment|AND|
Condition02=X-MDAEMON-DELIVER-TO|contains local account|AND|
Action01=run a program|"-1,0,0","C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file c:\Temp\RenameAttachments.ps1 $MESSAGEFILENAME$"param( [string]$MSGFileName = "C:\MDaemon\Queues\Bad\md5001000002293.msg" ) ################################################################################################################################ ################################################################################################################################ ## RemoveSpacesfromAttachmentNames ## ## September 10, 2023 ## ## Copyright MDaemon Technologies 2023 ## ## ## ## This script is designed to be ran by the content filter in MDaemon. It accepts the path to a message file as a parameter. ## ## The script extracts all attachments from the passed message and replaces all spaces in the filename with an underscore ## ## and then reattaches the file. ## ## ## ## MDaemon Technologies offers no warranty, provides no support, and is not responsible for any damages that may be arise ## ## from the use of this script. Use at your own risk. ## ## ## ################################################################################################################################ ################################################################################################################################ clear function Get-PrivateProfileString ($Path, $Category, $Key) { ############################################################################# ## ## Get-PrivateProfileString ## ## From Windows PowerShell Cookbook (O'Reilly) ## by Lee Holmes (http://www.leeholmes.com/guide) ## ############################################################################## <# .SYNOPSIS Retrieves an element from a standard .INI file .EXAMPLE Get-PrivateProfileString c:\windows\system32\tcpmon.ini ` "<Generic Network Card>" Name Generic Network Card #> Set-StrictMode -Version Latest ## The signature of the Windows API that retrieves INI ## settings $signature = @' [DllImport("kernel32.dll")] public static extern uint GetPrivateProfileString( string lpAppName, string lpKeyName, string lpDefault, StringBuilder lpReturnedString, uint nSize, string lpFileName); '@ ## Create a new type that lets us access the Windows API function $type = Add-Type -MemberDefinition $signature ` -Name Win32Utils -Namespace GetPrivateProfileString ` -Using System.Text -PassThru ## The GetPrivateProfileString function needs a StringBuilder to hold ## its output. Create one, and then invoke the method $builder = New-Object System.Text.StringBuilder 1024 $null = $type::GetPrivateProfileString($category, $key, "", $builder, $builder.Capacity, $path) ## Return the output $builder.ToString() } function GetRegistryValue($Key, $Name){ Log "Checking $Key" if(Test-Path $Key) { $Value = (Get-ItemProperty $Key -Name $Name).$Name if($Value -eq $null) { #This is included to clear the error that is set when the $Key exists but the $Name does not. $Error.Clear() } } if(!(Test-Path $Key) -or ($Value -eq $null) -or ($Value.Length -eq 0)) { $Base = Split-Path (Split-Path $Key) $Leaf2 = Split-Path $key -Leaf $Leaf1 = Split-Path (Split-Path $key) -Leaf $SysWownode = Join-Path (Join-Path (Join-Path $Base "Wow6432Node") $Leaf1) $Leaf2 if(Test-Path $SysWownode) { Log "The registry key value is empty or does not exist, checking $SysWownode." $Value = (Get-ItemProperty $SysWowNode -Name $Name).$Name if(($Value -eq $null) -or ($Value.Length -eq 0)) { Log "We can't find the registry key values, the script will now stop." exit } else { $Error.Clear() return $Value } } else { Log "We can't find the registry key values, the script will now stop." exit } } else { return $Value } } function Log($string, $color){ if($string -ne $null) { if($global:LoggedScriptStarting -ne "Yes") { $global:LoggedScriptStarting = "Yes" Log "Starting Script run at $MyDate.`r`n" } if ($color -eq $null) { $color = "White" } write-host $string -ForegroundColor $color if ($LogFile -ne $null) { $string | out-file -Filepath $LogFile -append } } } function Load-EmlFile ($MSGFileName){ if($MSGFileName -eq "" -or (!(Test-Path $MSGFileName))) { Log "The File name, $MSGFileName, is empty or does not exist. This is a critical error. The script will now exit." exit } $AdoDbStream = New-Object -ComObject ADODB.Stream $AdoDbStream.Type = 1 $AdoDbStream.Open() $AdoDbStream.LoadFromFile($MSGFileName) $CdoMessage = New-Object -ComObject CDO.Message $CdoMessage.DataSource.OpenObject($ADoDBStream,"_Stream") $AdoDbStream.Close() return $CdoMessage } function Save-EmlFile ($Message, $OutputFile) { Log "Saving updated message to disk as $OutputFile" $Message.GetStream().SaveToFile($OutputFile,2) } $MDINIPath = GetRegistryValue "HKLM:\SOFTWARE\Alt-N Technologies\MDaemon" "IniPath" $TempPath = Get-PrivateProfileString $MDINIPath "Directories" "Temp" $LogPath = Get-PrivateProfileString $MDINIPath "Directories" "LogFiles" $CurrentDate = Get-Date $LogFileDate = (Get-Date -Format yyyy-MM-dd) $LogFile = join-path $LogPath "MDaemon-$LogFileDate-Compress-Attachments.log" $OutputFile = $MSGFileName #"C:\MDaemon\Queues\Bad\pd35000003756.msg" Log "The MDaemon INI path is: $MDINIPath" Log "The Temp path is: $TempPath" Log "The Log path is: $LogPath" Log "Loading $MSGFileName" $MSG = Load-EmlFile $MSGFileName $MSGID = $MSG.Fields.Item("urn:schemas:mailheader:Message-ID").Value Log "The message ID is $MSGID." $Attachments = $MSG.Attachments if($Attachments.Count -gt 0) { Log "There were $($Attachments.Count) attachments found." $AttachPath = Join-Path $TempPath "RenameAttachments" if(!(Test-Path $AttachPath)) { Log "Creating $AttachPath." New-Item $AttachPath -ItemType directory } Log "The attachment path is: $AttachPath" Foreach($Attachment in $Attachments) { $AttachmentFileName = $($Attachment.FileName) Log "Found an attachment named $AttachmentFileName" if($AttachmentFileName.contains(" ")){ $FileAttachPath = Join-Path $AttachPath $AttachmentFileName Log "Saving to $FileAttachPath." $Attachment.SavetoFile($FileAttachPath) $NewName = $AttachmentFileName.replace(" ","_") Log "Renaming to $NewName" Rename-Item -Path $FileAttachPath –NewName $NewName $NewFileAttachPath = Join-Path $AttachPath $NewName Log "Attaching $NewFileAttachPath to email." $MSG.AddAttachment($NewFileAttachPath) #Log "Removing $AttachmentFilename from $MSGFileName" #$Attachment.Delete() Remove-Item $NewFileAttachPath -Force -ErrorAction SilentlyContinue } } Save-EmlFile $MSG $OutputFile } else { Log "No attachments were found in $MSGFileName with Message ID of $MSGID. Nothing is being done." } $CurrentDate = Get-Date Log "`r`nEnding Script run at $CurrentDate." Log "----------"