diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,26 @@
 # Revision history for haskell-amqp-utils
 
+## 0.6.3.2  -- 2021-10-25
+
+* update README
+
+## 0.6.3.1  -- 2021-09-08
+
+* avoid setCurrentDirectory which is not thread-safe
+* start watch before initial scan
+* put filename without directory into filename header
+
+## 0.6.3.0  -- 2021-09-06
+
+* watch multiple dirs in hotfolder mode
+* drop hinotify < 0.3.10 compatibility
+* use RawFilePath for file names
+* fix handling of non-ascii filenames in agitprop hotfolder
+
+## 0.6.2.4  -- 2021-08-30
+
+* depend on tls >= 1.5.0 (thread safety for writes)
+
 ## 0.6.2.2  -- 2021-08-25
 
 * agitprop: option to move sent file to another dir instead of just removing
diff --git a/Network/AMQP/Utils/Helpers.hs b/Network/AMQP/Utils/Helpers.hs
--- a/Network/AMQP/Utils/Helpers.hs
+++ b/Network/AMQP/Utils/Helpers.hs
@@ -1,28 +1,32 @@
 {-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE OverloadedStrings #-}
 
 module Network.AMQP.Utils.Helpers where
 
 import           Control.Concurrent
-import qualified Control.Exception          as X
+import qualified Control.Exception                as X
 import           Control.Monad
-import qualified Data.ByteString.Lazy.Char8 as BL
-import qualified Data.ByteString.UTF8       as BS
-import           Data.Int                   (Int64)
+import qualified Data.ByteString.Char8            as BS
+import qualified Data.ByteString.Lazy.Char8       as BL
+import qualified Data.ByteString.UTF8             as BU
+import           Data.Int                         (Int64)
 import           Data.List
-import qualified Data.Map                   as M
+import qualified Data.Map                         as M
 import           Data.Maybe
-import qualified Data.Text                  as T
+import qualified Data.Text                        as T
 import           Data.Time
 import           Data.Time.Clock.POSIX
-import           Data.Word                  (Word16)
+import           Data.Word                        (Word16)
 import           Network.AMQP
 import           Network.AMQP.Types
 import           Network.AMQP.Utils.Options
-import           Network.Socket             (PortNumber)
-import           System.Directory           (removeFile)
-import           System.Environment         (getEnvironment)
+import           Network.Socket                   (PortNumber)
+import           System.Directory                 (removeFile)
+import           System.Environment               (getEnvironment)
 import           System.Exit
+import           System.FilePath.Posix.ByteString (RawFilePath)
 import           System.IO
+import           System.Posix.IO.ByteString
 import           System.Process
 
 -- | print config parameters
@@ -47,14 +51,30 @@
   printparam _ Nothing  = return ()
   printparam x (Just y) = printparam x y
 
+instance Flexprint BS.ByteString where
+  flexprint = BS.hPutStrLn stderr
+  empty = BS.null
+
 instance Flexprint String where
   flexprint = hPutStrLn stderr
   empty = null
 
+instance Flexprint [BS.ByteString] where
+  flexprint = flexprint . BS.unwords
+  empty = null
+
 instance Flexprint [String] where
   flexprint = flexprint . unwords
   empty = null
 
+instance Flexprint [Maybe BS.ByteString] where
+  flexprint = flexprint . catMaybes
+  empty = null . catMaybes
+
+instance Flexprint [Maybe String] where
+  flexprint = flexprint . catMaybes
+  empty = null . catMaybes
+
 instance Flexprint T.Text where
   flexprint = flexprint . T.unpack
   empty = T.null
@@ -124,7 +144,7 @@
 
 -- | showing a FieldValue
 valueshow :: FieldValue -> String
-valueshow (FVString value)     = BS.toString value
+valueshow (FVString value)     = BU.toString value
 valueshow (FVInt8 value)       = show value
 valueshow (FVInt16 value)      = show value
 valueshow (FVInt32 value)      = show value
@@ -401,3 +421,21 @@
     (forever (threadDelay 600000000) >>
      return (X.toException $ X.ErrorCall "not reached"))
     return
+
+-- | extract first input file in case only one is needed
+firstInputFile :: [(RawFilePath,String,String)] -> RawFilePath
+firstInputFile []          = "-"
+firstInputFile ((x,_,_):_) = x
+
+-- | read RawFilePath to Lazy ByteString
+readFileRawLazy :: RawFilePath -> IO BL.ByteString
+readFileRawLazy path = do
+  h <- openFd path ReadOnly Nothing defaultFlags >>= fdToHandle
+  hSetBinaryMode h True
+  BL.hGetContents h
+  where
+    defaultFlags = OpenFileFlags { System.Posix.IO.ByteString.append = False
+                                 , exclusive = False
+                                 , noctty = True
+                                 , nonBlock = False
+                                 , trunc = False }
diff --git a/Network/AMQP/Utils/Options.hs b/Network/AMQP/Utils/Options.hs
--- a/Network/AMQP/Utils/Options.hs
+++ b/Network/AMQP/Utils/Options.hs
@@ -1,18 +1,21 @@
+{-# LANGUAGE OverloadedStrings #-}
+
 module Network.AMQP.Utils.Options where
 
-import qualified Data.ByteString.Char8 as BS
+import qualified Data.ByteString.Char8            as BS
 import           Data.Default.Class
-import           Data.Int              (Int64)
-import qualified Data.Map              as M
+import           Data.Int                         (Int64)
+import qualified Data.Map                         as M
 import           Data.Maybe
-import           Data.Text             (Text, pack)
-import           Data.Version          (showVersion)
-import           Data.Word             (Word16)
+import           Data.Text                        (Text, pack)
+import           Data.Version                     (showVersion)
+import           Data.Word                        (Word16)
 import           Network.AMQP
 import           Network.AMQP.Types
-import           Network.Socket        (PortNumber)
-import           Paths_amqp_utils      (version)
+import           Network.Socket                   (PortNumber)
+import           Paths_amqp_utils                 (version)
 import           System.Console.GetOpt
+import           System.FilePath.Posix.ByteString (RawFilePath)
 
 portnumber :: Args -> PortNumber
 portnumber a
@@ -43,7 +46,7 @@
     , additionalArgs  :: [String]
     , connectionName  :: Maybe String
     , tmpQName        :: String
-    , inputFile       :: String
+    , inputFiles      :: [(RawFilePath,String,String)]
     , outputFile      :: String
     , lineMode        :: Bool
     , confirm         :: Bool
@@ -60,7 +63,7 @@
     , msgexp          :: Maybe Text
     , msgheader       :: Maybe FieldTable
     , fnheader        :: [String]
-    , suffix          :: [String]
+    , suffix          :: [BS.ByteString]
     , magic           :: Bool
     , persistent      :: Maybe DeliveryMode
     , ack             :: Bool
@@ -70,7 +73,7 @@
     , simple          :: Bool
     , cleanupTmpFile  :: Bool
     , removeSentFile  :: Bool
-    , moveSentFileTo  :: Maybe FilePath
+    , moveSentFileTo  :: Maybe RawFilePath
     , initialScan     :: Bool
     }
 
@@ -97,7 +100,7 @@
       []
       Nothing
       ""
-      "-"
+      []
       "-"
       False
       False
@@ -199,8 +202,8 @@
     , Option
         ['f']
         ["inputfile"]
-        (ReqArg (\s o -> o {inputFile = s}) "INPUTFILE")
-        ("Message input file (default: " ++ (inputFile def) ++ ")"))
+        (ReqArg (\s o -> o {inputFiles = (BS.pack s,currentExchange o,rKey o):(inputFiles o)}) "INPUTFILE")
+        ("Message input file (default: <stdin>)"))
   , ( "p"
     , Option
         ['O']
@@ -310,13 +313,13 @@
     , Option
         ['S']
         ["suffix"]
-        (ReqArg (\s o -> o {suffix = s : (suffix o)}) "SUFFIX")
+        (ReqArg (\s o -> o {suffix = (BS.pack s) : (suffix o)}) "SUFFIX")
         "Allowed file suffixes in hotfolder mode")
   , ( "a"
     , Option
         ['u']
         ["remove", "move"]
-        (OptArg (\s o -> o {removeSentFile = True, moveSentFileTo = s}) "DIR")
+        (OptArg (\s o -> o {removeSentFile = True, moveSentFileTo = fmap BS.pack s}) "DIR")
         ("Remove (or move to DIR) sent file in hotfolder mode"))
   , ( "a"
     , Option
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -15,7 +15,7 @@
     Options:
       -r BINDINGKEY  --bindingkey=BINDINGKEY          AMQP binding key
       -X[EXE]        --execute[=EXE]                  Callback Script File (implies -t) (-X without arg: /usr/lib/haskell-amqp-utils/callback)
-      -a ARG         --args=ARG                       additional argument for -X callback
+      -a ARG         --args=ARG, --arg=ARG            additional argument for -X callback
       -t[DIR]        --tempdir[=DIR], --target[=DIR]  tempdir (default: no file creation, -t without arg: /tmp)
       -f INT         --prefetch=INT                   Prefetch count. (0=unlimited, 1=off, default: 1)
       -A             --ack                            Toggle ack messages (default: True)
@@ -78,7 +78,7 @@
 
     Options:
       -r ROUTINGKEY    --routingkey=ROUTINGKEY            AMQP routing key
-      -f INPUTFILE     --inputfile=INPUTFILE              Message input file (default: -)
+      -f INPUTFILE     --inputfile=INPUTFILE              Message input file (default: <stdin>)
       -l               --linemode                         Toggle line-by-line mode (default: False)
       -C               --confirm                          Toggle confirms (default: False)
                        --msgid=ID                         Message ID
@@ -123,6 +123,8 @@
 
 Line-by-line mode sends one message per INPUTFILE line.
 
+In "hotfolder mode" multiple directories can be watched and sent with distinct routingkeys.
+
 #### examples
 
 Send a message containing a file and put the filename into a fileName
@@ -130,32 +132,39 @@
 
     agitprop -x amq.topic -r test -F fileName -f agitprop.hs
 
+Watch two directories dir1 and dir2 and send files from dir1 with routingkey r1
+and files from dir2 with routingkey r2, ignoring everything which is not *.txt
+or *.zip, and set Content-Type and Content-Encoding automatically, and move all
+sent files to subdir "done" (dir1/done and dir2/done, respectively):
+
+    agitprop -x amq.topic -F fileName -m -S .txt -S .zip -d -udone -r r1 -f dir1 -r r2 -f dir2
+
 ### plane
 An RPC client.
 
     plane [options]
 
     Options:
-      -r ROUTINGKEY    --routingkey=ROUTINGKEY    AMQP routing key
-      -f INPUTFILE     --inputfile=INPUTFILE      Message input file (default: -)
-      -O OUTPUTFILE    --outputfile=OUTPUTFILE    Message output file (default: -)
-      -t SECONDS       --rpc_timeout=SECONDS      How long to wait for reply (default: 5.0)
-                       --corrid=CORRID            Message CorrelationID
-                       --exp=EXP                  Message Expiration
-      -h HEADER=VALUE  --header=HEADER=VALUE      Message Headers
-      -l INT           --charlimit=INT            limit number of shown body chars (default: unlimited)
-      -x EXCHANGE      --exchange=EXCHANGE        AMQP Exchange (default: "")
-      -o SERVER        --server=SERVER            AMQP Server (default: localhost)
-      -y VHOST         --vhost=VHOST              AMQP Virtual Host (default: /)
-      -p PORT          --port=PORT                Server Port Number (default: 5672)
-      -T               --tls                      Toggle TLS (default: False)
-      -c CERTFILE      --cert=CERTFILE            TLS Client Certificate File
-      -k KEYFILE       --key=KEYFILE              TLS Client Private Key File
-      -U USERNAME      --user=USERNAME            Username for Auth
-      -P PASSWORD      --pass=PASSWORD            Password for Auth
-      -s INT           --heartbeats=INT           heartbeat interval (0=disable, default: set by server)
-      -n NAME          --name=NAME                connection name, will be shown in RabbitMQ web interface
-      -w SECONDS       --connect_timeout=SECONDS  timeout for establishing initial connection (default: 600)
+      -r ROUTINGKEY, -Q ROUTINGKEY  --routingkey=ROUTINGKEY, --qname=ROUTINGKEY  AMQP routing key
+      -f INPUTFILE                  --inputfile=INPUTFILE                        Message input file (default: <stdin>)
+      -O OUTPUTFILE                 --outputfile=OUTPUTFILE                      Message output file (default: -)
+      -t SECONDS                    --rpc_timeout=SECONDS                        How long to wait for reply (default: 5.0)
+                                    --corrid=CORRID                              Message CorrelationID
+                                    --exp=EXP                                    Message Expiration
+      -h HEADER=VALUE               --header=HEADER=VALUE                        Message Headers
+      -l INT                        --charlimit=INT                              limit number of shown body chars (default: unlimited)
+      -x EXCHANGE                   --exchange=EXCHANGE                          AMQP Exchange (default: "")
+      -o SERVER                     --server=SERVER                              AMQP Server (default: localhost)
+      -y VHOST                      --vhost=VHOST                                AMQP Virtual Host (default: /)
+      -p PORT                       --port=PORT                                  Server Port Number (default: 5672)
+      -T                            --tls                                        Toggle TLS (default: False)
+      -c CERTFILE                   --cert=CERTFILE                              TLS Client Certificate File
+      -k KEYFILE                    --key=KEYFILE                                TLS Client Private Key File
+      -U USERNAME                   --user=USERNAME                              Username for Auth
+      -P PASSWORD                   --pass=PASSWORD                              Password for Auth
+      -s INT                        --heartbeats=INT                             heartbeat interval (0=disable, default: set by server)
+      -n NAME                       --name=NAME                                  connection name, will be shown in RabbitMQ web interface
+      -w SECONDS                    --connect_timeout=SECONDS                    timeout for establishing initial connection (default: 600)
 
 #### examples
 
@@ -170,7 +179,7 @@
 
     Options:
       -X[EXE]       --execute[=EXE]                  Callback Script File (implies -t) (-X without arg: /usr/lib/haskell-amqp-utils/callback)
-      -a ARG        --args=ARG                       additional argument for -X callback
+      -a ARG        --args=ARG, --arg=ARG            additional argument for -X callback
       -t[DIR]       --tempdir[=DIR], --target[=DIR]  tempdir (default: no file creation, -t without arg: /tmp)
       -f INT        --prefetch=INT                   Prefetch count. (0=unlimited, 1=off, default: 1)
       -A            --ack                            Toggle ack messages (default: True)
diff --git a/agitprop.hs b/agitprop.hs
--- a/agitprop.hs
+++ b/agitprop.hs
@@ -3,35 +3,32 @@
 
 -- generic AMQP publisher
 import           Control.Concurrent
-import qualified Control.Exception             as X
-import qualified Data.ByteString.Lazy.Char8    as BL
-#if linux_HOST_OS
-#if MIN_VERSION_hinotify(0,3,10)
-import qualified Data.ByteString.Char8         as BS
-#endif
-import           Data.List                     (isSuffixOf)
-#endif
+import qualified Control.Exception                as X
+import           Control.Monad                    (forM_)
+import qualified Data.ByteString.Lazy.Char8       as BL
+import qualified RawFilePath.Directory            as RD
+import qualified Data.ByteString.Char8            as BS
+import qualified Data.Map                         as M
 import           Data.Maybe
-import qualified Data.Text                     as T
+import qualified Data.Text                        as T
 import           Data.Time
 import           Data.Time.Clock.POSIX
-import           Data.Version                  (showVersion)
-import           Data.Word                     (Word64)
+import           Data.Version                     (showVersion)
+import           Data.Word                        (Word64)
 import           Magic
 import           Network.AMQP
 import           Network.AMQP.Types
 import           Network.AMQP.Utils.Connection
 import           Network.AMQP.Utils.Helpers
 import           Network.AMQP.Utils.Options
-import           Paths_amqp_utils              (version)
-import           System.Directory
+import           Paths_amqp_utils                 (version)
 import           System.Environment
 import           System.Exit
-import           System.FilePath.Posix
+import           System.FilePath.Posix.ByteString
 #if linux_HOST_OS
 import           System.INotify
 #endif
-import qualified System.Posix.Files            as F
+import qualified System.Posix.Files.ByteString    as F
 
 main :: IO ()
 main = do
@@ -41,23 +38,6 @@
   printparam "client version" ["amqp-utils", showVersion version]
   printparam "routing key" $ rKey args
   printparam "exchange" $ currentExchange args
-  isDir <-
-    if inputFile args == "-"
-      then return False
-      else F.getFileStatus (inputFile args) >>= return . F.isDirectory
-  if isDir
-    then printparam "hotfolder" (inputFile args) >>
-         printparam "initial scan" (initialScan args) >>
-         if isNothing (moveSentFileTo args)
-           then printparam "remove sent file" (removeSentFile args)
-           else printparam "move sent file to" (moveSentFileTo args)
-    else printparam
-           "input file"
-           [ inputFile args
-           , if (lineMode args)
-               then "(line-by-line)"
-               else ""
-           ]
   (conn, chan) <- connect args
   addChannelExceptionHandler chan (X.throwTo tid)
   printparam "confirm mode" $ confirm args
@@ -66,40 +46,49 @@
       confirmSelect chan False
       addConfirmationListener chan confirmCallback
     else return ()
+  let inputFile' = firstInputFile (inputFiles args)
+  isDir <-
+    if inputFile' == "-"
+      then return False
+      else F.getFileStatus inputFile' >>= return . F.isDirectory
   let publishOneMsg =
         publishOneMsg' chan args {removeSentFile = removeSentFile args && isDir}
+  if isDir
+    then do
+      printparam "hotfolder mode" True
+      printparam "initial scan" (initialScan args)
+      if isNothing (moveSentFileTo args)
+        then printparam "remove sent file" (removeSentFile args)
+        else printparam "move sent file to" (moveSentFileTo args)
+    else printparam
+           "input file"
+           [ inputFile'
+           , if (lineMode args)
+               then "(line-by-line)"
+               else ""
+           ]
   X.catch
     (if isDir
        then do
 #if linux_HOST_OS
-         setCurrentDirectory (inputFile args)
-         if (initialScan args)
-           then getDirectoryContents "." >>=
-                mapM_ (\fn -> handleFile publishOneMsg (suffix args) fn)
-           else return ()
-         inotify <- initINotify
-         wd <-
-           addWatch
-             inotify
-             [CloseWrite, MoveIn]
-             "."
-             (handleEvent publishOneMsg (suffix args))
-         hr $ "BEGIN watching " ++ (inputFile args)
+         wds <- mapM (watchHotfolder args publishOneMsg) (inputFiles args)
          sleepingBeauty >>= printparam "exception"
-         removeWatch wd
-         hr $ "END watching " ++ (inputFile args)
+         forM_ wds (\(wd,folder) -> do
+           removeWatch wd
+           printparam "END watching" folder
+           )
 #else
          X.throw (X.ErrorCall "ERROR: watching a directory is only supported in Linux")
 #endif
        else do
          hr $ "BEGIN sending"
          messageFile <-
-           if inputFile args == "-"
+           if inputFile' == "-"
              then BL.getContents
-             else BL.readFile (inputFile args)
+             else readFileRawLazy inputFile'
          if (lineMode args)
-           then mapM_ (publishOneMsg Nothing) (BL.lines messageFile)
-           else publishOneMsg (Just (inputFile args)) messageFile
+           then mapM_ (publishOneMsg (currentExchange args) (rKey args) Nothing) (BL.lines messageFile)
+           else publishOneMsg (currentExchange args) (rKey args) (Just (inputFile')) messageFile
          hr "END sending")
     exceptionHandler
   -- all done. wait and close.
@@ -108,6 +97,30 @@
     else return ()
   X.catch (closeConnection conn) exceptionHandler
 
+#if linux_HOST_OS
+-- | watch a hotfolder
+watchHotfolder ::
+     Args
+  -> (String -> String -> Maybe RawFilePath -> BL.ByteString -> IO ())
+  -> (RawFilePath, String, String)
+  -> IO (WatchDescriptor, RawFilePath)
+watchHotfolder args publishOneMsg (folder, exchange, rkey) = do
+  printparam "hotfolder" folder
+  inotify <- initINotify
+  wd <-
+   addWatch
+     inotify
+     [CloseWrite, MoveIn]
+     folder
+     (handleEvent (publishOneMsg exchange rkey) (suffix args) folder)
+  hr "BEGIN watching"
+  if (initialScan args)
+   then RD.listDirectory folder >>=
+        mapM_ (\fn -> handleFile (publishOneMsg exchange rkey) (suffix args) (folder </> fn))
+   else return ()
+  return (wd,folder)
+#endif
+
 -- | A handler for clean exit
 exceptionHandler :: AMQPException -> IO ()
 exceptionHandler (ChannelClosedException Normal txt) =
@@ -127,58 +140,57 @@
         else "this"
     , show ackType
     ]
-
 #if linux_HOST_OS
 -- | Hotfolder event handler
 handleEvent ::
-     (Maybe String -> BL.ByteString -> IO ()) -> [String] -> Event -> IO ()
+     (Maybe RawFilePath -> BL.ByteString -> IO ()) -> [BS.ByteString] -> RawFilePath -> Event -> IO ()
 -- just handle closewrite and movedin events
-#if MIN_VERSION_hinotify(0,3,10)
-handleEvent func suffixes (Closed False (Just fileName) True) =
-  handleFile func suffixes (BS.unpack fileName)
-handleEvent func suffixes (MovedIn False fileName _) =
-  handleFile func suffixes (BS.unpack fileName)
-#else
-handleEvent func suffixes (Closed False (Just fileName) True) =
-  handleFile func suffixes fileName
-handleEvent func suffixes (MovedIn False fileName _) =
-  handleFile func suffixes fileName
-#endif
-handleEvent _ _ _ = return ()
+handleEvent func suffixes folder (Closed False (Just fileName) True) =
+  handleFile func suffixes (folder </> fileName)
+handleEvent func suffixes folder (MovedIn False fileName _) =
+  handleFile func suffixes (folder </> fileName)
+handleEvent _ _ _ _ = return ()
 
 -- | Hotfolder file handler
 handleFile ::
-     (Maybe String -> BL.ByteString -> IO ()) -> [String] -> FilePath -> IO ()
-handleFile _ _ ('.':_) = return () -- ignore hidden files
+     (Maybe RawFilePath -> BL.ByteString -> IO ()) -> [BS.ByteString] -> RawFilePath -> IO ()
 handleFile func suffixes@(_:_) fileName =
-  if any (flip isSuffixOf fileName) suffixes
+  if (any (flip BS.isSuffixOf fileName) suffixes) && not ("." `BS.isPrefixOf` fileName)
     then handleFile func [] fileName
     else return ()
 handleFile func [] fileName =
   X.catch
-    (BL.readFile fileName >>= func (Just fileName))
-    (\e -> printparam "exception in handleFile" (e :: X.IOException))
+    (readFileRawLazy fileName >>= func (Just fileName))
+    (\e -> printparam "exception while processing" fileName >> printparam "exception in handleFile" (e :: X.IOException))
 #endif
 
 -- | Publish one message with our settings
-publishOneMsg' :: Channel -> Args -> Maybe FilePath -> BL.ByteString -> IO ()
-publishOneMsg' chan a fn content = do
+publishOneMsg' ::
+     Channel
+  -> Args
+  -> String
+  -> String
+  -> Maybe RawFilePath
+  -> BL.ByteString
+  -> IO ()
+publishOneMsg' chan a exchange rkey fn content = do
   printparam "sending" fn
   (mtype, mencoding) <-
-    if (magic a) && isJust fn
+    if (magic a)
       then do
+        let firstchunk = if BL.null content then BS.empty else head $ BL.toChunks content
         m <- magicOpen [MagicMimeType]
         magicLoadDefault m
-        t <- magicFile m (fromJust fn)
+        t <- BS.useAsCStringLen firstchunk (magicCString m)
         magicSetFlags m [MagicMimeEncoding]
-        e <- magicFile m (fromJust fn)
+        e <- BS.useAsCStringLen firstchunk (magicCString m)
         return (Just (T.pack t), Just (T.pack e))
       else return ((contenttype a), (contentencoding a))
   now <- getCurrentTime >>= return . floor . utcTimeToPOSIXSeconds
   publishMsg
     chan
-    (T.pack $ currentExchange a)
-    (T.pack $ rKey a)
+    (T.pack $ exchange)
+    (T.pack $ rkey)
     newMsg
       { msgBody = content
       , msgDeliveryMode = persistent a
@@ -194,20 +206,25 @@
       , msgPriority = prio a
       , msgCorrelationID = corrid a
       , msgExpiration = msgexp a
-      , msgHeaders = substheader (fnheader a) fn $ msgheader a
+      , msgHeaders = substheader (fnheader a) (fmap takeFileName fn) $ msgheader a
       } >>=
     printparam "sent"
   removeSentFileIfRequested (removeSentFile a) (moveSentFileTo a) fn
   where
     substheader ::
-         [String] -> Maybe String -> Maybe FieldTable -> Maybe FieldTable
+         [String] -> Maybe BS.ByteString -> Maybe FieldTable -> Maybe FieldTable
     substheader (s:r) (Just fname) old =
-      substheader r (Just fname) (addheader old (s ++ "=" ++ fname))
+      substheader r (Just fname) (addheader' old s fname)
     substheader _ _ old = old
     removeSentFileIfRequested False _ _ = return ()
     removeSentFileIfRequested True _ Nothing = return ()
     removeSentFileIfRequested True Nothing (Just fname) =
-      printparam "removing" fname >> removeFile fname
+      printparam "removing" fname >> RD.removeFile fname
     removeSentFileIfRequested True (Just path) (Just fname) =
-      printparam "moving" (fname ++ " to " ++ path) >>
-      renameFile fname (replaceDirectory fname path)
+      printparam "moving" [fname,"to",path] >>
+      F.rename fname (replaceDirectory fname ((takeDirectory fname) </> path))
+    addheader' :: Maybe FieldTable -> String -> BS.ByteString -> Maybe FieldTable
+    addheader' Nothing k v =
+      Just $ FieldTable $ M.singleton (T.pack k) (FVString v)
+    addheader' (Just (FieldTable oldheader)) k v =
+      Just $ FieldTable $ M.insert (T.pack k) (FVString v) oldheader
diff --git a/amqp-utils.cabal b/amqp-utils.cabal
--- a/amqp-utils.cabal
+++ b/amqp-utils.cabal
@@ -1,6 +1,6 @@
 name:                amqp-utils
 
-version:             0.6.2.2
+version:             0.6.3.2
 
 synopsis:            AMQP toolset for the command line
 
@@ -45,10 +45,12 @@
                        directory,
                        bytestring,
                        utf8-string,
+                       filepath-bytestring,
                        x509-system,
                        network > 2.6,
-                       tls >= 1.3.9,
-                       amqp >=0.19
+                       tls >= 1.5.0,
+                       amqp >=0.19,
+                       unix >= 2.7
 
   ghc-options:         -threaded -Wall
 
@@ -72,14 +74,16 @@
                        filepath,
                        bytestring,
                        utf8-string,
+                       rawfilepath,
+                       filepath-bytestring,
                        x509-system,
                        network > 2.6,
-                       tls >= 1.3.9,
+                       tls >= 1.5.0,
                        amqp >=0.19,
                        unix >= 2.7,
                        magic
   if os(linux)
-    build-depends:     hinotify >= 0.3.8
+    build-depends:     hinotify >= 0.3.10
 
   ghc-options:         -threaded -Wall
 
@@ -102,9 +106,10 @@
                        directory,
                        bytestring,
                        utf8-string,
+                       filepath-bytestring,
                        x509-system,
                        network > 2.6,
-                       tls >= 1.3.9,
+                       tls >= 1.5.0,
                        amqp >=0.19,
                        unix >= 2.7
 
@@ -129,9 +134,10 @@
                        directory,
                        bytestring,
                        utf8-string,
+                       filepath-bytestring,
                        x509-system,
                        network > 2.6,
-                       tls >= 1.3.9,
+                       tls >= 1.5.0,
                        amqp >=0.19,
                        unix >= 2.7
 
diff --git a/plane.hs b/plane.hs
--- a/plane.hs
+++ b/plane.hs
@@ -36,11 +36,12 @@
       printparam "exchange" $ currentExchange args
       bindQueue chan q (T.pack $ currentExchange args) q
     else return ()
-  printparam "input file" $ inputFile args
+  let inputFile' = firstInputFile (inputFiles args)
+  printparam "input file" $ inputFile'
   message <-
-    if inputFile args == "-"
+    if inputFile' == "-"
       then BL.getContents
-      else BL.readFile (inputFile args)
+      else readFileRawLazy inputFile'
   printparam "output file" $ outputFile args
   h <-
     if outputFile args == "-"
