diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,3 +1,7 @@
+## 0.4.12
+
+* Add function to add attachments with content id [#48](https://github.com/snoyberg/mime-mail/pull/48)
+
 ## 0.4.11
 
 * Export renderAddress as a utility (e.g. Reply-to) [#44](https://github.com/snoyberg/mime-mail/pull/44)
diff --git a/Network/Mail/Mime.hs b/Network/Mail/Mime.hs
--- a/Network/Mail/Mime.hs
+++ b/Network/Mail/Mime.hs
@@ -25,8 +25,10 @@
       -- * Utilities
     , addPart
     , addAttachment
+    , addAttachmentCid
     , addAttachments
     , addAttachmentBS
+    , addAttachmentBSCid
     , addAttachmentsBS
     , renderAddress
     , htmlPart
@@ -251,7 +253,7 @@
 -- Since 0.4.3
 showAddress :: Address -> Builder
 showAddress a = mconcat
-    [ maybe mempty ((`mappend` fromByteString " ") . encodedWord) (addressName a)
+    [ maybe mempty ((fromByteString " " <>) . encodedWord) (addressName a)
     , fromByteString "<"
     , fromText (addressEmail a)
     , fromByteString ">"
@@ -430,10 +432,26 @@
 -- | Add an attachment from a file and construct a 'Part'.
 addAttachment :: Text -> FilePath -> Mail -> IO Mail
 addAttachment ct fn mail = do
-    content <- L.readFile fn
-    let part = Part ct Base64 (Just $ T.pack (takeFileName fn)) [] content
+    part <- getAttachmentPart ct fn
     return $ addPart [part] mail
 
+-- | Add an attachment from a file and construct a 'Part'
+-- with the specified content id in the Content-ID header.
+--
+-- @since 0.4.12
+addAttachmentCid :: Text -- ^ content type
+                 -> FilePath -- ^ file name
+                 -> Text -- ^ content ID
+                 -> Mail
+                 -> IO Mail
+addAttachmentCid ct fn cid mail =
+  getAttachmentPart ct fn >>= (return.addToMail.addHeader) 
+  where 
+    addToMail part = addPart [part] mail
+    addHeader part = part { partHeaders = header:ph }
+      where ph = partHeaders part
+    header = ("Content-ID", T.concat ["<", cid, ">"])
+
 addAttachments :: [(Text, FilePath)] -> Mail -> IO Mail
 addAttachments xs mail = foldM fun mail xs
   where fun m (c, f) = addAttachment c f m
@@ -446,14 +464,39 @@
                 -> L.ByteString -- ^ content
                 -> Mail -> Mail
 addAttachmentBS ct fn content mail =
-    let part = Part ct Base64 (Just fn) [] content
+    let part = getAttachmentPartBS ct fn content
     in addPart [part] mail
 
+-- | @since 0.4.12
+addAttachmentBSCid :: Text -- ^ content type
+                -> Text -- ^ file name
+                -> L.ByteString -- ^ content
+                -> Text -- ^ content ID
+                -> Mail -> Mail
+addAttachmentBSCid ct fn content cid mail =
+    let part = addHeader $ getAttachmentPartBS ct fn content
+    in addPart [part] mail
+    where
+      addHeader part = part { partHeaders = header:ph }
+        where ph = partHeaders part
+      header = ("Content-ID", T.concat ["<", cid, ">"])
+
 -- |
 -- Since 0.4.7
 addAttachmentsBS :: [(Text, Text, L.ByteString)] -> Mail -> Mail
 addAttachmentsBS xs mail = foldl fun mail xs
   where fun m (ct, fn, content) = addAttachmentBS ct fn content m
+
+getAttachmentPartBS :: Text
+                    -> Text
+                    -> L.ByteString
+                    -> Part
+getAttachmentPartBS ct fn content = Part ct Base64 (Just fn) [] content
+
+getAttachmentPart :: Text -> FilePath -> IO Part
+getAttachmentPart ct fn = do
+    content <- L.readFile fn
+    return $ getAttachmentPartBS ct (T.pack (takeFileName fn)) content
 
 data QP = QPPlain S.ByteString
         | QPNewline
diff --git a/mime-mail.cabal b/mime-mail.cabal
--- a/mime-mail.cabal
+++ b/mime-mail.cabal
@@ -1,5 +1,5 @@
 Name:                mime-mail
-Version:             0.4.11
+Version:             0.4.12
 Synopsis:            Compose MIME email messages.
 description:         Hackage documentation generation is not reliable. For up to date documentation, please see: <http://www.stackage.org/package/mime-mail>.
 Homepage:            http://github.com/snoyberg/mime-mail
