diff --git a/.travis.yml b/.travis.yml
--- a/.travis.yml
+++ b/.travis.yml
@@ -1,3 +1,76 @@
-language: haskell
+# This file has been generated -- see https://github.com/hvr/multi-ghc-travis
+language: c
+sudo: false
+
+cache:
+  directories:
+    - $HOME/.cabsnap
+    - $HOME/.cabal/packages
+
+before_cache:
+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/build-reports.log
+  - rm -fv $HOME/.cabal/packages/hackage.haskell.org/00-index.tar
+
+matrix:
+  include:
+    - env: CABALVER=1.24 GHCVER=8.4.3
+      compiler: ": #GHC 8.4.3"
+      addons: {apt: {packages: [cabal-install-1.24,ghc-8.4.3], sources: [hvr-ghc]}}
+
 before_install:
-  - sudo apt-get install -qq libicu-dev
+ - unset CC
+ - export PATH=/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
+
+install:
+ - cabal --version
+ - echo "$(ghc --version) [$(ghc --print-project-git-commit-id 2> /dev/null || echo '?')]"
+ - if [ -f $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz ];
+   then
+     zcat $HOME/.cabal/packages/hackage.haskell.org/00-index.tar.gz >
+          $HOME/.cabal/packages/hackage.haskell.org/00-index.tar;
+   fi
+ - travis_retry cabal update -v
+ - sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
+ - cabal install --only-dependencies --enable-tests --enable-benchmarks --dry -v > installplan.txt
+ - sed -i -e '1,/^Resolving /d' installplan.txt; cat installplan.txt
+
+# check whether current requested install-plan matches cached package-db snapshot
+ - if diff -u installplan.txt $HOME/.cabsnap/installplan.txt;
+   then
+     echo "cabal build-cache HIT";
+     rm -rfv .ghc;
+     cp -a $HOME/.cabsnap/ghc $HOME/.ghc;
+     cp -a $HOME/.cabsnap/lib $HOME/.cabsnap/share $HOME/.cabsnap/bin $HOME/.cabal/;
+   else
+     echo "cabal build-cache MISS";
+     rm -rf $HOME/.cabsnap;
+     mkdir -p $HOME/.ghc $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin;
+     cabal install --only-dependencies --enable-tests --enable-benchmarks;
+   fi
+
+# snapshot package-db on cache miss
+ - if [ ! -d $HOME/.cabsnap ];
+   then
+      echo "snapshotting package-db to build-cache";
+      mkdir $HOME/.cabsnap;
+      cp -a $HOME/.ghc $HOME/.cabsnap/ghc;
+      cp -a $HOME/.cabal/lib $HOME/.cabal/share $HOME/.cabal/bin installplan.txt $HOME/.cabsnap/;
+   fi
+
+# Here starts the actual work to be performed for the package under test;
+# any command which exits with a non-zero exit code causes the build to fail.
+script:
+ - if [ -f configure.ac ]; then autoreconf -i; fi
+ - cabal configure --enable-tests --enable-benchmarks -v2  # -v2 provides useful information for debugging
+ - cabal build   # this builds all libraries and executables (including tests/benchmarks)
+ - cabal test
+ - cabal check
+ - cabal sdist   # tests that a source-distribution can be generated
+
+# Check that the resulting source distribution can be built & installed.
+# If there are no other `.tar.gz` files in `dist`, this can be even simpler:
+# `cabal install --force-reinstalls dist/*-*.tar.gz`
+ - SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
+   (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
+
+# EOF
diff --git a/email-header.cabal b/email-header.cabal
--- a/email-header.cabal
+++ b/email-header.cabal
@@ -1,18 +1,19 @@
 name:                email-header
-version:             0.4.0
+version:             0.4.1
 synopsis:            Parsing and rendering of email and MIME headers
 description:         Parsing and rendering of email and MIME headers
 license:             BSD3
 license-file:        LICENSE
-author:              Kyle Raftogianis <kylerafto@gmail.com>
-maintainer:          Kyle Raftogianis <kylerafto@gmail.com>
+author:              Kyle Raftogianis
+maintainer:          Kyle Raftogianis <knrafto@gmail.com>
 stability:           experimental
 homepage:            http://github.com/knrafto/email-header
 bug-reports:         http://github.com/knrafto/email-header/issues
-copyright:           Copyright (c) 2014 Kyle Raftogianis
+copyright:           Copyright (c) 2014-2018 Kyle Raftogianis
 category:            Network
 build-type:          Simple
 cabal-version:       >= 1.8
+tested-with:         GHC == 8.4.3
 
 extra-source-files:
   .gitignore
@@ -29,7 +30,7 @@
 
   build-depends:
     attoparsec        >= 0.9   && < 1,
-    base              >= 4.8   && < 5,
+    base              >= 4.6   && < 5,
     base64-bytestring >= 0.1.2 && < 2,
     bytestring        >= 0.10  && < 0.11,
     case-insensitive,
diff --git a/src/Network/Email/Header/Doc.hs b/src/Network/Email/Header/Doc.hs
--- a/src/Network/Email/Header/Doc.hs
+++ b/src/Network/Email/Header/Doc.hs
@@ -33,7 +33,6 @@
 import qualified Data.ByteString.Lazy.Builder as B
 import qualified Data.ByteString.Lazy         as LB
 import           Data.List                    (intersperse)
-import           Data.Monoid
 import           Data.String
 import qualified Data.Text.Lazy               as L
 import qualified Data.Text.Lazy.Encoding      as L
@@ -82,9 +81,12 @@
     | Cat Doc Doc
     | Union Doc Doc
 
+instance Semigroup Doc where
+  (<>) = Cat
+
 instance Monoid Doc where
     mempty  = Empty
-    mappend = Cat
+    mappend = (<>)
 
 instance IsString Doc where
     fromString = string
diff --git a/src/Network/Email/Header/Layout.hs b/src/Network/Email/Header/Layout.hs
--- a/src/Network/Email/Header/Layout.hs
+++ b/src/Network/Email/Header/Layout.hs
@@ -10,16 +10,17 @@
 
 import Prelude     hiding (span, break)
 
-import Data.Monoid
-
 type LayoutStep a = Int -> (Int -> Bool, a)
 
 -- | An abstract type representing a lazy layout.
 newtype Layout a = Layout { runLayout :: LayoutStep a -> LayoutStep a }
 
+instance Semigroup (Layout a) where
+    (<>) a b = Layout $ runLayout a . runLayout b
+
 instance Monoid (Layout a) where
     mempty      = Layout id
-    mappend a b = Layout $ runLayout a . runLayout b
+    mappend     = (<>)
 
 -- | Run a layout with an initial position.
 layout :: Monoid a => Int -> Layout a -> a
diff --git a/src/Network/Email/Header/Parser.hs b/src/Network/Email/Header/Parser.hs
--- a/src/Network/Email/Header/Parser.hs
+++ b/src/Network/Email/Header/Parser.hs
@@ -50,7 +50,6 @@
 import           Data.List
 import qualified Data.Map.Strict                  as Map
 import           Data.Maybe
-import           Data.Monoid
 import qualified Data.Text                        as T
 import           Data.Text.Encoding
 import qualified Data.Text.Lazy                   as L (Text, fromChunks)
diff --git a/src/Network/Email/Header/Render.hs b/src/Network/Email/Header/Render.hs
--- a/src/Network/Email/Header/Render.hs
+++ b/src/Network/Email/Header/Render.hs
@@ -1,3 +1,4 @@
+{-# LANGUAGE CPP               #-}
 {-# LANGUAGE OverloadedStrings #-}
 -- | Rendering common header fields.
 -- This module is intended to be imported qualified:
@@ -48,6 +49,10 @@
 import qualified Data.ByteString.Lazy.Builder as B
 import           Data.CaseInsensitive         (CI)
 import qualified Data.CaseInsensitive         as CI
+#if MIN_VERSION_base(4,8,0)
+#else
+import           Data.Monoid
+#endif
 import qualified Data.Text.Lazy               as L
 import           Data.Time.LocalTime
 
diff --git a/tests/Tests.hs b/tests/Tests.hs
--- a/tests/Tests.hs
+++ b/tests/Tests.hs
@@ -1,9 +1,14 @@
+{-# LANGUAGE CPP               #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 module Main
     ( main
     ) where
 
+#if MIN_VERSION_base(4,8,0)
+#else
+import           Control.Applicative
+#endif
 import           Control.Exception
 import qualified Data.ByteString.Char8       as B
 import           Data.CaseInsensitive        (CI)
