Changing the extension of an attachment with the content filter | MDaemon Technologies, Ltd.

Changing the extension of an attachment with the content filter


  • When compressing an attachment with the content filter, the file name can be changed, but the extension is fixed to ZIP. I would like an option to change the extension. Also, when compressing an attachment, I would like to insert a message such as "Example: Attachment compressed" into the message body.

    In some industries in Japan, it is customary to change the extension of compressed files from "ZIP to ZI_" before sending and receiving them.



  • The only way to have the files be renamed to ZI_ will be by using a custom script and having the content filter execute it.  

    Below is a script that should be very close to what you need.  Please be careful, I have done very limited testing with this script.  I would reccomend that you test it thoroughly before using it in your production environment.  The script creates its own log file called MDaemon-$DATE$-Compress-Attachments.log in the MDaemon\Logs directory.

    In order to use the script you will first need to download and install 7-Zip on your MDaemon server.  Then create a content filter rule like the following:

    [Rule030]
    RuleName=Compress Files in ZI_
    Enable=Yes
    ThisRuleCondition=All
    ProcessQueue=BOTH
    Condition01=body|has attachment|AND|
    Action01=run a program|"-1,0,0","C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -file c:\Temp\CompressAttachmentsRenameZIP.ps1 $MESSAGEFILENAME$"

    You'll want to adjust the conditions on the content filter rule to meet your needs.  If you want to add a warning about attachments being compressed you can adjust this rule to do it using the "Add a warning to the top of the message" action.

     

    param(
        [string]$MSGFileName
    )
    
    ################################################################################################################################
    ################################################################################################################################
    ## Put attachments in compressed file using ZI_ extension v 1.0.0                                                             ##
    ## August 15, 2024	     									   		                                                          ##
    ## Copyright MDaemon Technologies	2024											                                          ##
    ## 	                                                                                                                          ##
    ## 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 places them in a zip file that is then                     ##
    ## attached to the email.                                                                                                     ##
    ##                                                                                                                            ##
    ## 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)
    }
    
    function AddFiletoArchive ($FileName, $Archive) {
    
        Log "Adding $FileName to $Archive using the following arguments:"
        $Args = "a `"$Archive`" `"$FileName`""
        Log $Args 
         
        $EXE1 = Start-Process $7Zip -ArgumentList $Args -Wait
    
        Log $EXE1.ExitCode
    }
    
    Function GET-RandomString($Length, $SourceData) {
        
        For ($loop=1; $loop –le $Length; $loop++) 
        {
            $TempPassword+=($SourceData | GET-RANDOM)
        }
    
        return $TempPassword
    }
    
    $MDINIPath = GetRegistryValue "HKLM:\SOFTWARE\Alt-N Technologies\MDaemon" "IniPath"
    $TempPath = Get-PrivateProfileString $MDINIPath "Directories" "Temp"
    $RAWPath = Get-PrivateProfileString $MDINIPath "Directories" "Raw"
    $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"
    $alphabet=$NULL;For ($a=65;$a –le 90;$a++) {$alphabet+=,[char][byte]$a }
    
    #$MSGFileName = "C:\MDaemon\Queues\Bad\pd35000003755.msg"
    $OutputFile = $MSGFileName #"C:\MDaemon\Queues\Bad\pd35000003756.msg"
    
    $7Zip = "$env:ProgramFiles\7-Zip\7z.exe"
    
    if(!(Test-Path $7zip))
    {
        
        $7Zip = "$env:ProgramW6432\7-Zip\7z.exe"
        Log "$7Zip does not exist. Trying $7Zip."
        if(!(Test-Path $7Zip))
        {
            Log "$7zip does not exist."
            Log "Error: Could not find 7z.exe.  The script will now exist."
            exit
        }
    }
    
    Log "The path to the 7-Zip EXE is $7Zip."
    Log "The MDaemon INI path is: $MDINIPath"
    Log "The Temp path is: $TempPath"
    Log "The Raw Files path is: $RAWPath"
    Log "The Log path is: $LogPath"
    
    Log "Cleaning up empty directories from $TempPath"
    Get-ChildItem $TempPath -recurse | Where-Object {$_.PSIsContainer -eq $True -and $_.GetFiles().Count -eq 0} | Remove-Item -Force -ErrorAction SilentlyContinue
    
    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."
       
        $From = $MSG.Fields.Item("urn:schemas:mailheader:From").Value
        $To = $MSG.Fields.Item("urn:schemas:mailheader:x-mdaemon-deliver-to").Value
        $MSGSubject = $MSG.Subject 
        
        $ArchiveFileName = $Attachments.Item(1).FileName
        Log "The name of the attachment is $ArchiveFileName."
        
        $ArchiveFileName = [io.path]::ChangeExtension($ArchiveFileName, "zip")
           
        Log "Setting the Archive file name to $ArchiveFileName."
    
        $RandFolder = GET-RandomString "10" $alphabet
    
        $AttachPath = Join-Path $TempPath $RandFolder
    
        if(!(Test-Path $AttachPath))
        {
            Log "Creating a folder named $RandFolder in the Temp path."
            $null = New-Item $AttachPath -ItemType directory
        }
    
        Log "The attachment path is: $AttachPath"
        $ArchivePath = Join-Path $AttachPath $ArchiveFileName
        Log "The archive file name is: $ArchivePath"
        Log "Creating an Archive file"
    
        Foreach($Attachment in $Attachments)
        {
            $Count = 1
            $AttachmentFileName = $($Attachment.FileName)
            Log "Found an attachment named $AttachmentFileName"
            
            $FileAttachPath = Join-Path $AttachPath $AttachmentFileName
            $AttachmentFileNameWOExtension = [System.IO.Path]::GetFileNameWithoutExtension($AttachmentFileName)
            $AttachmentFileNameExtension = [System.IO.Path]::GetExtension($AttachmentFileName)
    
            While((Test-Path $FileAttachPath) -or ($AttachmentFileName -eq $ArchiveFileName))
            {
    
                $AttachmentFileName = $AttachmentFileNameWOExtension + "(" + $Count + ")" + $AttachmentFileNameExtension
    
                $FileAttachPath = Join-Path $AttachPath $AttachmentFileName
    
                $Count++
            }      
         
            Log "Saving to $FileAttachPath."
            $Attachment.SavetoFile($FileAttachPath)
                
            AddFiletoArchive $FileAttachPath $ArchivePath
        
        }
    
        if(Test-Path $ArchivePath)
        {
    
            Log "Removing all attachments from $MSGFileName"
            $Attachments.DeleteAll()
        
            $NewName = $ArchivePath.replace(".zip",".zi_")
    
            Log "Renaming to $NewName"
            Rename-Item -Path $ArchivePath –NewName $NewName
    
            Log "Adding $NewName attachment to $MSGFileName"
            $MSG.AddAttachment($NewName)
        
            Save-EmlFile $MSG $OutputFile
    
        }
        else
        {
            Log "Error: The compressed file could not be found at $ArchivePath. The script will now exit without making any changes."
    
        }
    
        Log "Removing all files and folders from $AttachPath"
        Remove-Item "$AttachPath\*" -Recurse -Force -ErrorAction SilentlyContinue
    
        if(Test-Path $AttachPath)
        {
            Log "Removing $AttachPath from disk."
            Remove-Item $AttachPath -Force -Recurse -ErrorAction SilentlyContinue
        }
    
    
    
    }
    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 "----------"

     

     


Please login to reply this topic!