packages feed

smtps-gmail 1.1.1 → 1.2.0

raw patch · 3 files changed

+619/−642 lines, 3 files

Files

Network/Mail/Client/Gmail.hs view
@@ -9,643 +9,620 @@ -- | A simple SMTP Client for sending Gmail. module Network.Mail.Client.Gmail (sendGmail) where -import Control.Monad (foldM_, forM, liftM, void)-import Crypto.Random.AESCtr (makeSystem)-import Data.ByteString.Char8 (lines, unpack)-import Data.ByteString.Base64.Lazy (encode)-import Data.ByteString.Lazy.Char8 (ByteString, readFile)-import Data.ByteString.Lazy.Search (replace)-import Data.Char (isDigit, isSpace)-import Data.Default (def)-import Data.Monoid ((<>))-import Data.Text as Strict (Text, pack)-import Data.Text.Lazy as Lazy (Text, fromChunks)-import Data.Text.Lazy.Encoding (encodeUtf8)-import Network (PortID(PortNumber), connectTo)-import Network.Mail.Mime hiding (renderMail)-import Network.TLS-import Network.TLS.Extra-import Prelude hiding (any, lines, readFile)-import System.FilePath (takeExtension, takeFileName)-import System.IO hiding (readFile)-import System.Timeout (timeout)---- | Send an email from your Gmail account using the simple---   message transfer protocol with transport layer security.---   Below is an example using ghci, where Alice sends an---   Excel spreadsheet to Bob.------ > >>> :set -XOverloadedStrings--- > >>> :module Network.Mail.Mime Network.Mail.Client.Gmail--- > >>> sendGmail "alice" "password" (Address (Just "Alice") "alice@gmail.com") [Address (Just "Bob") "bob@example.com"] [] [] "Excel Spreadsheet" "Hi Bob,\n\nThe Excel spreadsheet is attached.\n\nRegards,\n\nAlice" ["spreadsheet.xls"] Nothing----sendGmail-  :: Lazy.Text   -- ^ username-  -> Lazy.Text   -- ^ password-  -> Address     -- ^ from-  -> [Address]   -- ^ to-  -> [Address]   -- ^ cc-  -> [Address]   -- ^ bcc-  -> Strict.Text -- ^ subject-  -> Lazy.Text   -- ^ body-  -> [FilePath]  -- ^ attachments-  -> Maybe Int   -- ^ timeout in microseconds-  -> IO ()-sendGmail user pass from to cc bcc subject body attach lim = do-  hdl   <- connectTo "smtp.gmail.com" $ PortNumber 587-  sys   <- makeSystem-  ctx   <- contextNew hdl params sys-  _MAIL <- renderMail from to cc bcc subject body attach-  hSetBuffering hdl LineBuffering-  -----------------------------  -- BEGIN MESSAGE EXCHANGE ---  -----------------------------  sendSMTP  hdl "EHLO"       >> recvSMTP  hdl lim "220"-                             >> recvSMTP  hdl lim "250"-  sendSMTP  hdl "STARTTLS"   >> recvSMTP  hdl lim "220"-  handshake ctx-  sendSMTPS ctx "EHLO"       >> recvSMTPS ctx lim "250"-  sendSMTPS ctx "AUTH LOGIN" >> recvSMTPS ctx lim "334"-  sendSMTPS ctx _USERNAME    >> recvSMTPS ctx lim "334"-  sendSMTPS ctx _PASSWORD    >> recvSMTPS ctx lim "235"-  sendSMTPS ctx _FROM        >> recvSMTPS ctx lim "250"-  sendSMTPS ctx _TO          >> recvSMTPS ctx lim "250"-  sendSMTPS ctx "DATA"       >> recvSMTPS ctx lim "354"-  sendSMTPS ctx _MAIL        >> recvSMTPS ctx lim "250"-  sendSMTPS ctx "QUIT"       >> recvSMTPS ctx lim "221"-  -----------------------------  --- END MESSAGE EXCHANGE ----  -----------------------------  bye ctx-  contextClose ctx-  hClose hdl-  where _USERNAME  = encode $ encodeUtf8 user-        _PASSWORD  = encode $ encodeUtf8 pass-        _FROM      = "MAIL FROM: " <> angleBracket [from]-        _TO        = "RCPT TO: "   <> angleBracket (to ++ cc ++ bcc)---- | Display the first email address in the given list using angle bracket formatting.-angleBracket :: [Address] -> ByteString-angleBracket = \ case [] -> ""; (Address _ email:_) -> "<" <> encodeUtf8 (fromChunks [email]) <> ">"---- | Render an email using the RFC 2822 message format.-renderMail-  :: Address     -- ^ from-  -> [Address]   -- ^ to-  -> [Address]   -- ^ cc-  -> [Address]   -- ^ bcc-  -> Strict.Text -- ^ subject-  -> Lazy.Text   -- ^ body-  -> [FilePath]  -- ^ attachments-  -> IO ByteString-renderMail from to cc bcc subject body attach = do-  parts <- forM attach $ \ path -> do-    content <- readFile path-    let mime = getMime $ takeExtension path-        file = Just . pack $ takeFileName path-    return $! [Part mime Base64 file [] content]-  let plain = [Part "text/plain; charset=utf-8" QuotedPrintableText Nothing [] $ encodeUtf8 body]-  mail <- renderMail' . Mail from to cc bcc headers $ plain : parts-  return $! replace "\n." ("\n.."::ByteString) mail <> "\r\n.\r\n"-  where headers = [("Subject",subject)]---- | Send an unencrypted message using the simple message transfer protocol.-sendSMTP-  :: Handle -- ^ connection-  -> String -- ^ message-  -> IO ()-sendSMTP = hPutStrLn---- | Receive an unencrypted message using the simple message transfer protocol.-recvSMTP-  :: Handle    -- ^ connection-  -> Maybe Int -- ^ timeout in microseconds-  -> String    -- ^ expected reply code-  -> IO ()-recvSMTP hdl lim code = void $-  step [] where-  step accum = do-    mval <- maybe (liftM Just) timeout lim $ hGetLine hdl-    case mval of-      Nothing    -> fail "recvSMTP: connection timeout"-      Just reply -> match code reply step accum---- | Send an encrypted message using the simple message transfer protocol.-sendSMTPS-  :: Context    -- ^ connection-  -> ByteString -- ^ message-  -> IO ()-sendSMTPS ctx msg = sendData ctx $ msg <> "\r\n"---- | Receive an encrypted message using the simple message transfer protocol.-recvSMTPS-  :: Context   -- ^ connection-  -> Maybe Int -- ^ timeout in microseconds-  -> String    -- ^ expected reply code-  -> IO ()-recvSMTPS ctx lim code = do-  mval <- maybe (liftM Just) timeout lim $ recvData ctx-  case mval of-    Nothing      -> fail "recvSMTPS: connection timeout"-    Just replies -> foldM_ step [] $ lines replies-    -- NOTE: Here we assume that the whole response arrives in-    -- one TLS packet. That assumption is not necessarily true.-    where step accum reply = match code (unpack reply) return accum---- | A convenient type synonym.-type Continuation = [String] -> IO [String]---- | Match reply codes and perform continuation, termination, and failure case analysis.-match-  :: String       -- ^ expected reply code-  -> String       -- ^ reply-  -> Continuation -- ^ continuation-  -> [String]     -- ^ accumulator-  -> IO [String]-match code reply continuation accum =-  if not (null suffix) && head suffix == '-'-  then continuation $ drop 1 suffix:accum-  else if prefix == code && "" /= code-       then return []-       else mismatch code prefix $ suffix:accum-       where (prefix, suffix) = break (not . isDigit) reply---- | Raise an exception for mismatched reply codes.-mismatch-  :: String   -- ^ expected reply code-  -> String   -- ^ received reply code-  -> [String] -- ^ messages-  -> IO [String]-mismatch code other replies = fail $-  if null code-  then "mismatch: missing expected reply code."-  else "mismatch: expected reply code " ++ code ++-   (if null other-    then ", but no reply code was received"-    else ", but received reply code " ++ other) ++-    case filter (not . null) $ map strip replies of-      []     -> "."-      (r:rs) -> ": " ++ foldl step (strip r) rs ++ "."-      where strip = dropWhile isSpace . filter (/='\r')-            step accum = flip (++) $ "; " ++ accum---- | TLS client parameters.-params :: ClientParams -params = (defaultParamsClient "smtp.gmail.com" "587")-  { clientSupported  = def { supportedCiphers      = ciphersuite_all }-  , clientShared     = def { sharedValidationCache = noValidate      }-  } where noValidate = ValidationCache (\_ _ _ -> return ValidationCachePass)-                                       (\_ _ _ -> return ())---- | Get the mime type for the given file extension.-getMime :: String -> Strict.Text-getMime = \ case-  ".3dm"       -> "x-world/x-3dmf"-  ".3dmf"      -> "x-world/x-3dmf"-  ".a"         -> "application/octet-stream"-  ".aab"       -> "application/x-authorware-bin"-  ".aam"       -> "application/x-authorware-map"-  ".aas"       -> "application/x-authorware-seg"-  ".abc"       -> "text/vnd.abc"-  ".acgi"      -> "text/html"-  ".afl"       -> "video/animaflex"-  ".ai"        -> "application/postscript"-  ".aif"       -> "audio/aiff"-  ".aifc"      -> "audio/aiff"-  ".aiff"      -> "audio/aiff"-  ".aim"       -> "application/x-aim"-  ".aip"       -> "text/x-audiosoft-intra"-  ".ani"       -> "application/x-navi-animation"-  ".aos"       -> "application/x-nokia-9000-communicator-add-on-software"-  ".aps"       -> "application/mime"-  ".arc"       -> "application/octet-stream"-  ".arj"       -> "application/arj"-  ".art"       -> "image/x-jg"-  ".asf"       -> "video/x-ms-asf"-  ".asm"       -> "text/x-asm"-  ".asp"       -> "text/asp"-  ".asx"       -> "application/x-mplayer2"-  ".au"        -> "audio/basic"-  ".avi"       -> "application/x-troff-msvideo"-  ".avs"       -> "video/avs-video"-  ".bcpio"     -> "application/x-bcpio"-  ".bin"       -> "application/mac-binary"-  ".bm"        -> "image/bmp"-  ".bmp"       -> "image/bmp"-  ".boo"       -> "application/book"-  ".book"      -> "application/book"-  ".boz"       -> "application/x-bzip2"-  ".bsh"       -> "application/x-bsh"-  ".bz"        -> "application/x-bzip"-  ".bz2"       -> "application/x-bzip2"-  ".c"         -> "text/plain"-  ".c++"       -> "text/plain"-  ".cat"       -> "application/vnd.ms-pki.seccat"-  ".cc"        -> "text/plain"-  ".ccad"      -> "application/clariscad"-  ".cco"       -> "application/x-cocoa"-  ".cdf"       -> "application/cdf"-  ".cer"       -> "application/pkix-cert"-  ".cha"       -> "application/x-chat"-  ".chat"      -> "application/x-chat"-  ".class"     -> "application/java"-  ".com"       -> "application/octet-stream"-  ".conf"      -> "text/plain"-  ".cpio"      -> "application/x-cpio"-  ".cpp"       -> "text/x-c"-  ".cpt"       -> "application/mac-compactpro"-  ".crl"       -> "application/pkcs-crl"-  ".crt"       -> "application/pkix-cert"-  ".csh"       -> "application/x-csh"-  ".css"       -> "application/x-pointplus"-  ".cxx"       -> "text/plain"-  ".dcr"       -> "application/x-director"-  ".deepv"     -> "application/x-deepv"-  ".def"       -> "text/plain"-  ".der"       -> "application/x-x509-ca-cert"-  ".dif"       -> "video/x-dv"-  ".dir"       -> "application/x-director"-  ".dl"        -> "video/dl"-  ".doc"       -> "application/msword"-  ".dot"       -> "application/msword"-  ".dp"        -> "application/commonground"-  ".drw"       -> "application/drafting"-  ".dump"      -> "application/octet-stream"-  ".dv"        -> "video/x-dv"-  ".dvi"       -> "application/x-dvi"-  ".dwf"       -> "drawing/x-dwf (old)"-  ".dwg"       -> "application/acad"-  ".dxf"       -> "application/dxf"-  ".dxr"       -> "application/x-director"-  ".el"        -> "text/x-script.elisp"-  ".elc"       -> "application/x-bytecode.elisp (compiled elisp)"-  ".env"       -> "application/x-envoy"-  ".eps"       -> "application/postscript"-  ".es"        -> "application/x-esrehber"-  ".etx"       -> "text/x-setext"-  ".evy"       -> "application/envoy"-  ".exe"       -> "application/octet-stream"-  ".f"         -> "text/plain"-  ".f77"       -> "text/x-fortran"-  ".f90"       -> "text/plain"-  ".fdf"       -> "application/vnd.fdf"-  ".fif"       -> "application/fractals"-  ".fli"       -> "video/fli"-  ".flo"       -> "image/florian"-  ".flx"       -> "text/vnd.fmi.flexstor"-  ".fmf"       -> "video/x-atomic3d-feature"-  ".for"       -> "text/plain"-  ".fpx"       -> "image/vnd.fpx"-  ".frl"       -> "application/freeloader"-  ".funk"      -> "audio/make"-  ".g"         -> "text/plain"-  ".g3"        -> "image/g3fax"-  ".gif"       -> "image/gif"-  ".gl"        -> "video/gl"-  ".gsd"       -> "audio/x-gsm"-  ".gsm"       -> "audio/x-gsm"-  ".gsp"       -> "application/x-gsp"-  ".gss"       -> "application/x-gss"-  ".gtar"      -> "application/x-gtar"-  ".gz"        -> "application/x-compressed"-  ".gzip"      -> "application/x-gzip"-  ".h"         -> "text/plain"-  ".hdf"       -> "application/x-hdf"-  ".help"      -> "application/x-helpfile"-  ".hgl"       -> "application/vnd.hp-hpgl"-  ".hh"        -> "text/plain"-  ".hlb"       -> "text/x-script"-  ".hlp"       -> "application/hlp"-  ".hpg"       -> "application/vnd.hp-hpgl"-  ".hpgl"      -> "application/vnd.hp-hpgl"-  ".hqx"       -> "application/binhex"-  ".hs"        -> "text/x-haskell"-  ".hta"       -> "application/hta"-  ".htc"       -> "text/x-component"-  ".htm"       -> "text/html"-  ".html"      -> "text/html"-  ".htmls"     -> "text/html"-  ".htt"       -> "text/webviewhtml"-  ".htx"       -> "text/html"-  ".ice"       -> "x-conference/x-cooltalk"-  ".ico"       -> "image/x-icon"-  ".idc"       -> "text/plain"-  ".ief"       -> "image/ief"-  ".iefs"      -> "image/ief"-  ".iges"      -> "application/iges"-  ".igs"       -> "application/iges"-  ".ima"       -> "application/x-ima"-  ".imap"      -> "application/x-httpd-imap"-  ".inf"       -> "application/inf"-  ".ins"       -> "application/x-internett-signup"-  ".ip"        -> "application/x-ip2"-  ".isu"       -> "video/x-isvideo"-  ".it"        -> "audio/it"-  ".iv"        -> "application/x-inventor"-  ".ivr"       -> "i-world/i-vrml"-  ".ivy"       -> "application/x-livescreen"-  ".jam"       -> "audio/x-jam"-  ".jav"       -> "text/plain"-  ".java"      -> "text/plain"-  ".jcm"       -> "application/x-java-commerce"-  ".jfif"      -> "image/jpeg"-  ".jfif-tbnl" -> "image/jpeg"-  ".jpe"       -> "image/jpeg"-  ".jpeg"      -> "image/jpeg"-  ".jpg"       -> "image/jpeg"-  ".jps"       -> "image/x-jps"-  ".js"        -> "application/x-javascript"-  ".jut"       -> "image/jutvision"-  ".kar"       -> "audio/midi"-  ".ksh"       -> "application/x-ksh"-  ".la"        -> "audio/nspaudio"-  ".lam"       -> "audio/x-liveaudio"-  ".latex"     -> "application/x-latex"-  ".lha"       -> "application/lha"-  ".lhx"       -> "application/octet-stream"-  ".list"      -> "text/plain"-  ".lma"       -> "audio/nspaudio"-  ".log"       -> "text/plain"-  ".lsp"       -> "application/x-lisp"-  ".lst"       -> "text/plain"-  ".lsx"       -> "text/x-la-asf"-  ".ltx"       -> "application/x-latex"-  ".lzh"       -> "application/octet-stream"-  ".lzx"       -> "application/lzx"-  ".m"         -> "text/plain"-  ".m1v"       -> "video/mpeg"-  ".m2a"       -> "audio/mpeg"-  ".m2v"       -> "video/mpeg"-  ".m3u"       -> "audio/x-mpequrl"-  ".man"       -> "application/x-troff-man"-  ".map"       -> "application/x-navimap"-  ".mar"       -> "text/plain"-  ".mbd"       -> "application/mbedlet"-  ".mc$"       -> "application/x-magic-cap-package-1.0"-  ".mcd"       -> "application/mcad"-  ".mcf"       -> "image/vasa"-  ".mcp"       -> "application/netmc"-  ".me"        -> "application/x-troff-me"-  ".mht"       -> "message/rfc822"-  ".mhtml"     -> "message/rfc822"-  ".mid"       -> "application/x-midi"-  ".midi"      -> "application/x-midi"-  ".mif"       -> "application/x-frame"-  ".mime"      -> "message/rfc822"-  ".mjf"       -> "audio/x-vnd.audioexplosion.mjuicemediafile"-  ".mjpg"      -> "video/x-motion-jpeg"-  ".mm"        -> "application/base64"-  ".mme"       -> "application/base64"-  ".mod"       -> "audio/mod"-  ".moov"      -> "video/quicktime"-  ".mov"       -> "video/quicktime"-  ".movie"     -> "video/x-sgi-movie"-  ".mp2"       -> "audio/mpeg"-  ".mp3"       -> "audio/mpeg3"-  ".mpa"       -> "audio/mpeg"-  ".mpc"       -> "application/x-project"-  ".mpe"       -> "video/mpeg"-  ".mpeg"      -> "video/mpeg"-  ".mpg"       -> "audio/mpeg"-  ".mpga"      -> "audio/mpeg"-  ".mpp"       -> "application/vnd.ms-project"-  ".mpt"       -> "application/x-project"-  ".mpv"       -> "application/x-project"-  ".mpx"       -> "application/x-project"-  ".mrc"       -> "application/marc"-  ".ms"        -> "application/x-troff-ms"-  ".mv"        -> "video/x-sgi-movie"-  ".my"        -> "audio/make"-  ".mzz"       -> "application/x-vnd.audioexplosion.mzz"-  ".nap"       -> "image/naplps"-  ".naplps"    -> "image/naplps"-  ".nc"        -> "application/x-netcdf"-  ".ncm"       -> "application/vnd.nokia.configuration-message"-  ".nif"       -> "image/x-niff"-  ".niff"      -> "image/x-niff"-  ".nix"       -> "application/x-mix-transfer"-  ".nsc"       -> "application/x-conference"-  ".nvd"       -> "application/x-navidoc"-  ".o"         -> "application/octet-stream"-  ".oda"       -> "application/oda"-  ".omc"       -> "application/x-omc"-  ".omcd"      -> "application/x-omcdatamaker"-  ".omcr"      -> "application/x-omcregerator"-  ".p"         -> "text/x-pascal"-  ".p10"       -> "application/pkcs10"-  ".p12"       -> "application/pkcs-12"-  ".p7a"       -> "application/x-pkcs7-signature"-  ".p7c"       -> "application/pkcs7-mime"-  ".p7m"       -> "application/pkcs7-mime"-  ".p7r"       -> "application/x-pkcs7-certreqresp"-  ".p7s"       -> "application/pkcs7-signature"-  ".part"      -> "application/pro_eng"-  ".pas"       -> "text/pascal"-  ".pbm"       -> "image/x-portable-bitmap"-  ".pcl"       -> "application/vnd.hp-pcl"-  ".pct"       -> "image/x-pict"-  ".pcx"       -> "image/x-pcx"-  ".pdb"       -> "chemical/x-pdb"-  ".pdf"       -> "application/pdf"-  ".pfunk"     -> "audio/make"-  ".pgm"       -> "image/x-portable-graymap"-  ".pic"       -> "image/pict"-  ".pict"      -> "image/pict"-  ".pkg"       -> "application/x-newton-compatible-pkg"-  ".pko"       -> "application/vnd.ms-pki.pko"-  ".pl"        -> "text/plain"-  ".plx"       -> "application/x-pixclscript"-  ".pm"        -> "image/x-xpixmap"-  ".pm4"       -> "application/x-pagemaker"-  ".pm5"       -> "application/x-pagemaker"-  ".png"       -> "image/png"-  ".pnm"       -> "application/x-portable-anymap"-  ".pot"       -> "application/mspowerpoint"-  ".pov"       -> "model/x-pov"-  ".ppa"       -> "application/vnd.ms-powerpoint"-  ".ppm"       -> "image/x-portable-pixmap"-  ".pps"       -> "application/mspowerpoint"-  ".ppt"       -> "application/mspowerpoint"-  ".ppz"       -> "application/mspowerpoint"-  ".pre"       -> "application/x-freelance"-  ".prt"       -> "application/pro_eng"-  ".ps"        -> "application/postscript"-  ".psd"       -> "application/octet-stream"-  ".pvu"       -> "paleovu/x-pv"-  ".pwz"       -> "application/vnd.ms-powerpoint"-  ".py"        -> "text/x-script.phyton"-  ".pyc"       -> "applicaiton/x-bytecode.python"-  ".qcp"       -> "audio/vnd.qcelp"-  ".qd3"       -> "x-world/x-3dmf"-  ".qd3d"      -> "x-world/x-3dmf"-  ".qif"       -> "image/x-quicktime"-  ".qt"        -> "video/quicktime"-  ".qtc"       -> "video/x-qtc"-  ".qti"       -> "image/x-quicktime"-  ".qtif"      -> "image/x-quicktime"-  ".ra"        -> "audio/x-pn-realaudio"-  ".ram"       -> "audio/x-pn-realaudio"-  ".ras"       -> "application/x-cmu-raster"-  ".rast"      -> "image/cmu-raster"-  ".rexx"      -> "text/x-script.rexx"-  ".rf"        -> "image/vnd.rn-realflash"-  ".rgb"       -> "image/x-rgb"-  ".rm"        -> "application/vnd.rn-realmedia"-  ".rmi"       -> "audio/mid"-  ".rmm"       -> "audio/x-pn-realaudio"-  ".rmp"       -> "audio/x-pn-realaudio"-  ".rng"       -> "application/ringing-tones"-  ".rnx"       -> "application/vnd.rn-realplayer"-  ".roff"      -> "application/x-troff"-  ".rp"        -> "image/vnd.rn-realpix"-  ".rpm"       -> "audio/x-pn-realaudio-plugin"-  ".rt"        -> "text/richtext"-  ".rtf"       -> "application/rtf"-  ".rtx"       -> "application/rtf"-  ".rv"        -> "video/vnd.rn-realvideo"-  ".s"         -> "text/x-asm"-  ".s3m"       -> "audio/s3m"-  ".saveme"    -> "application/octet-stream"-  ".sbk"       -> "application/x-tbook"-  ".scm"       -> "application/x-lotusscreencam"-  ".sdml"      -> "text/plain"-  ".sdp"       -> "application/sdp"-  ".sdr"       -> "application/sounder"-  ".sea"       -> "application/sea"-  ".set"       -> "application/set"-  ".sgm"       -> "text/sgml"-  ".sgml"      -> "text/sgml"-  ".sh"        -> "application/x-bsh"-  ".shar"      -> "application/x-bsh"-  ".shtml"     -> "text/html"-  ".sid"       -> "audio/x-psid"-  ".sit"       -> "application/x-sit"-  ".skd"       -> "application/x-koan"-  ".skm"       -> "application/x-koan"-  ".skp"       -> "application/x-koan"-  ".skt"       -> "application/x-koan"-  ".sl"        -> "application/x-seelogo"-  ".smi"       -> "application/smil"-  ".smil"      -> "application/smil"-  ".snd"       -> "audio/basic"-  ".sol"       -> "application/solids"-  ".spc"       -> "application/x-pkcs7-certificates"-  ".spl"       -> "application/futuresplash"-  ".spr"       -> "application/x-sprite"-  ".sprite"    -> "application/x-sprite"-  ".src"       -> "application/x-wais-source"-  ".ssi"       -> "text/x-server-parsed-html"-  ".ssm"       -> "application/streamingmedia"-  ".sst"       -> "application/vnd.ms-pki.certstore"-  ".step"      -> "application/step"-  ".stl"       -> "application/sla"-  ".stp"       -> "application/step"-  ".sv4cpio"   -> "application/x-sv4cpio"-  ".sv4crc"    -> "application/x-sv4crc"-  ".svf"       -> "image/vnd.dwg"-  ".svr"       -> "application/x-world"-  ".swf"       -> "application/x-shockwave-flash"-  ".t"         -> "application/x-troff"-  ".talk"      -> "text/x-speech"-  ".tar"       -> "application/x-tar"-  ".tbk"       -> "application/toolbook"-  ".tcl"       -> "application/x-tcl"-  ".tcsh"      -> "text/x-script.tcsh"-  ".tex"       -> "application/x-tex"-  ".texi"      -> "application/x-texinfo"-  ".texinfo"   -> "application/x-texinfo"-  ".text"      -> "application/plain"-  ".tgz"       -> "application/gnutar"-  ".tif"       -> "image/tiff"-  ".tiff"      -> "image/tiff"-  ".tr"        -> "application/x-troff"-  ".tsi"       -> "audio/tsp-audio"-  ".tsp"       -> "application/dsptype"-  ".tsv"       -> "text/tab-separated-values"-  ".turbot"    -> "image/florian"-  ".txt"       -> "text/plain"-  ".uil"       -> "text/x-uil"-  ".uni"       -> "text/uri-list"-  ".unis"      -> "text/uri-list"-  ".unv"       -> "application/i-deas"-  ".uri"       -> "text/uri-list"-  ".uris"      -> "text/uri-list"-  ".ustar"     -> "application/x-ustar"-  ".uu"        -> "application/octet-stream"-  ".uue"       -> "text/x-uuencode"-  ".vcd"       -> "application/x-cdlink"-  ".vcs"       -> "text/x-vcalendar"-  ".vda"       -> "application/vda"-  ".vdo"       -> "video/vdo"-  ".vew"       -> "application/groupwise"-  ".viv"       -> "video/vivo"-  ".vivo"      -> "video/vivo"-  ".vmd"       -> "application/vocaltec-media-desc"-  ".vmf"       -> "application/vocaltec-media-file"-  ".voc"       -> "audio/voc"-  ".vos"       -> "video/vosaic"-  ".vox"       -> "audio/voxware"-  ".vqe"       -> "audio/x-twinvq-plugin"-  ".vqf"       -> "audio/x-twinvq"-  ".vql"       -> "audio/x-twinvq-plugin"-  ".vrml"      -> "application/x-vrml"-  ".vrt"       -> "x-world/x-vrt"-  ".vsd"       -> "application/x-visio"-  ".vst"       -> "application/x-visio"-  ".vsw"       -> "application/x-visio"-  ".w60"       -> "application/wordperfect6.0"-  ".w61"       -> "application/wordperfect6.1"-  ".w6w"       -> "application/msword"-  ".wav"       -> "audio/wav"-  ".wb1"       -> "application/x-qpro"-  ".wbmp"      -> "image/vnd.wap.wbmp"-  ".web"       -> "application/vnd.xara"-  ".wiz"       -> "application/msword"-  ".wk1"       -> "application/x-123"-  ".wmf"       -> "windows/metafile"-  ".wml"       -> "text/vnd.wap.wml"-  ".wmlc"      -> "application/vnd.wap.wmlc"-  ".wmls"      -> "text/vnd.wap.wmlscript"-  ".wmlsc"     -> "application/vnd.wap.wmlscriptc"-  ".word"      -> "application/msword"-  ".wp"        -> "application/wordperfect"-  ".wp5"       -> "application/wordperfect"-  ".wp6"       -> "application/wordperfect"-  ".wpd"       -> "application/wordperfect"-  ".wq1"       -> "application/x-lotus"-  ".wri"       -> "application/mswrite"-  ".wrl"       -> "application/x-world"-  ".wrz"       -> "model/vrml"-  ".wsc"       -> "text/scriplet"-  ".wsrc"      -> "application/x-wais-source"-  ".wtk"       -> "application/x-wintalk"-  ".xbm"       -> "image/x-xbitmap"-  ".xdr"       -> "video/x-amt-demorun"-  ".xgz"       -> "xgl/drawing"-  ".xif"       -> "image/vnd.xiff"-  ".xl"        -> "application/excel"-  ".xla"       -> "application/excel"-  ".xlb"       -> "application/excel"-  ".xlc"       -> "application/excel"-  ".xld"       -> "application/excel"-  ".xlk"       -> "application/excel"-  ".xll"       -> "application/excel"-  ".xlm"       -> "application/excel"-  ".xls"       -> "application/excel"-  ".xlt"       -> "application/excel"-  ".xlv"       -> "application/excel"-  ".xlw"       -> "application/excel"-  ".xm"        -> "audio/xm"-  ".xml"       -> "application/xml"-  ".xmz"       -> "xgl/movie"-  ".xpix"      -> "application/x-vnd.ls-xpix"-  ".xpm"       -> "image/x-xpixmap"-  ".x-png"     -> "image/png"-  ".xsr"       -> "video/x-amt-showrun"-  ".xwd"       -> "image/x-xwd"-  ".xyz"       -> "chemical/x-pdb"-  ".z"         -> "application/x-compress"-  ".zip"       -> "application/x-compressed"-  ".zoo"       -> "application/octet-stream"-  ".zsh"       -> "text/x-script.zsh"-  _            -> "application/octet-stream"+import Control.Monad (foldM_, forM)+import Crypto.Random.AESCtr (makeSystem)+import Data.ByteString.Char8 (lines, unpack)+import Data.ByteString.Base64.Lazy (encode)+import Data.ByteString.Lazy.Char8 (ByteString, readFile)+import Data.ByteString.Lazy.Search (replace)+import Data.Char (isDigit, isSpace)+import Data.Default (def)+import Data.Monoid ((<>))+import Data.Text as Strict (Text, pack)+import Data.Text.Lazy as Lazy (Text, fromChunks)+import Data.Text.Lazy.Encoding (encodeUtf8)+import Network (PortID(PortNumber), connectTo)+import Network.Mail.Mime hiding (renderMail)+import Network.TLS+import Network.TLS.Extra+import Prelude hiding (any, lines, readFile)+import System.FilePath (takeExtension, takeFileName)+import System.IO hiding (readFile)++-- | Send an email from your Gmail account using the+--   simple message transfer protocol with transport+--   layer security. If you have 2-step verification+--   enabled on your account, then you will need to+--   retrieve an application specific password before+--   using this function. Below is an example using+--   ghci, where Alice sends an Excel spreadsheet to+--   Bob.+--+-- > >>> :set -XOverloadedStrings+-- > >>> :module Network.Mail.Mime Network.Mail.Client.Gmail+-- > >>> sendGmail "alice" "password" (Address (Just "Alice") "alice@gmail.com") [Address (Just "Bob") "bob@example.com"] [] [] "Excel Spreadsheet" "Hi Bob,\n\nThe Excel spreadsheet is attached.\n\nRegards,\n\nAlice" ["Spreadsheet.xls"]+--+sendGmail+   :: Lazy.Text   -- ^ username+   -> Lazy.Text   -- ^ password+   -> Address     -- ^ from+   -> [Address]   -- ^ to+   -> [Address]   -- ^ cc+   -> [Address]   -- ^ bcc+   -> Strict.Text -- ^ subject+   -> Lazy.Text   -- ^ body+   -> [FilePath]  -- ^ attachments+   -> IO ()+sendGmail user pass from to cc bcc subject body attach = do+   hdl   <- connectTo "smtp.gmail.com" $ PortNumber 587+   sys   <- makeSystem+   ctx   <- contextNew hdl params sys+   _MAIL <- renderMail from to cc bcc subject body attach+   hSetBuffering hdl LineBuffering+   ----------------------------+   -- BEGIN MESSAGE EXCHANGE --+   ----------------------------+   sendSMTP  hdl "EHLO"       >> recvSMTP  hdl "220"+                              >> recvSMTP  hdl "250"+   sendSMTP  hdl "STARTTLS"   >> recvSMTP  hdl "220"+   handshake ctx+   sendSMTPS ctx "EHLO"       >> recvSMTPS ctx "250"+   sendSMTPS ctx "AUTH LOGIN" >> recvSMTPS ctx "334"+   sendSMTPS ctx _USERNAME    >> recvSMTPS ctx "334"+   sendSMTPS ctx _PASSWORD    >> recvSMTPS ctx "235"+   sendSMTPS ctx _FROM        >> recvSMTPS ctx "250"+   sendSMTPS ctx _TO          >> recvSMTPS ctx "250"+   sendSMTPS ctx "DATA"       >> recvSMTPS ctx "354"+   sendSMTPS ctx _MAIL        >> recvSMTPS ctx "250"+   sendSMTPS ctx "QUIT"       >> recvSMTPS ctx "221"+   ----------------------------+   --- END MESSAGE EXCHANGE ---+   ----------------------------+   bye ctx+   contextClose ctx+   hClose hdl+   where _USERNAME  = encode $ encodeUtf8 user+         _PASSWORD  = encode $ encodeUtf8 pass+         _FROM      = "MAIL FROM: " <> angleBracket [from]+         _TO        = "RCPT TO: "   <> angleBracket (to ++ cc ++ bcc)++-- | Display the first email address in the given list using angle bracket formatting.+angleBracket :: [Address] -> ByteString+angleBracket = \ case [] -> ""; (Address _ email:_) -> "<" <> encodeUtf8 (fromChunks [email]) <> ">"++-- | Render an email using the RFC 2822 message format.+renderMail+   :: Address     -- ^ from+   -> [Address]   -- ^ to+   -> [Address]   -- ^ cc+   -> [Address]   -- ^ bcc+   -> Strict.Text -- ^ subject+   -> Lazy.Text   -- ^ body+   -> [FilePath]  -- ^ attachments+   -> IO ByteString+renderMail from to cc bcc subject body attach = do+   parts <- forM attach $ \ path -> do+      content <- readFile path+      let mime = getMime $ takeExtension path+          file = Just . pack $ takeFileName path+      return $! [Part mime Base64 file [] content]+   let plain = [Part "text/plain; charset=utf-8" QuotedPrintableText Nothing [] $ encodeUtf8 body]+   mail <- renderMail' . Mail from to cc bcc headers $ plain : parts+   return $! replace "\n." ("\n.."::ByteString) mail <> "\r\n.\r\n"+   where headers = [("Subject",subject)]++-- | Send an unencrypted message using the simple message transfer protocol.+sendSMTP :: Handle -> String -> IO ()+sendSMTP = hPutStrLn++-- | Receive an unencrypted message using the simple message transfer protocol.+recvSMTP :: Handle -> String -> IO ()+recvSMTP hdl code = go [] >> return ()+   where go accum = hGetLine hdl >>= \ reply -> match code reply go accum++-- | Send an encrypted message using the simple message transfer protocol.+sendSMTPS :: Context -> ByteString -> IO ()+sendSMTPS ctx msg = sendData ctx $ msg <> "\r\n"++-- | Receive an encrypted message using the simple message transfer protocol.+recvSMTPS :: Context -> String -> IO ()+recvSMTPS ctx code = recvData ctx >>= foldM_ step [] . lines+   where step accum reply = match code (unpack reply) return accum++-- | A convenient type synonym.+type Continuation = [String] -> IO [String]++-- | Match reply codes and perform continuation, termination, and failure case analysis.+match+   :: String       -- ^ expected reply code+   -> String       -- ^ actual reply code+   -> Continuation -- ^ continuation+   -> [String]     -- ^ accumulator+   -> IO [String]+match code reply go accum =+   if not (null suffix) && head suffix == '-'+   then go $ drop 1 suffix:accum+   else if prefix == code && "" /= code+        then return []+        else mismatch code prefix $ suffix:accum+        where (prefix, suffix) = break (not . isDigit) reply++-- | Raise an exception for mismatched reply codes.+mismatch+   :: String   -- ^ expected reply code+   -> String   -- ^ actual reply code+   -> [String] -- ^ messages+   -> IO [String]+mismatch code other replies = fail $+   if null code+   then "mismatch: missing expected reply code."+   else "mismatch: expected reply code " ++ code +++    (if null other+     then ", but no reply code was received"+     else ", but received reply code " ++ other) +++     case filter (not . null) $ map strip replies of+       []     -> "."+       (r:rs) -> ": " ++ foldl step (strip r) rs ++ "."+       where strip = dropWhile isSpace . filter (/='\r')+             step accum = flip (++) $ "; " ++ accum++-- | TLS client parameters.+params :: ClientParams +params = (defaultParamsClient "smtp.gmail.com" "587")+   { clientSupported  = def { supportedCiphers      = ciphersuite_all }+   , clientShared     = def { sharedValidationCache = noValidate      }+   } where noValidate = ValidationCache (\_ _ _ -> return ValidationCachePass)+                                        (\_ _ _ -> return ())++-- | Get the mime type for the given file extension.+getMime :: String -> Strict.Text+getMime = \ case+   ".3dm"       -> "x-world/x-3dmf"+   ".3dmf"      -> "x-world/x-3dmf"+   ".a"         -> "application/octet-stream"+   ".aab"       -> "application/x-authorware-bin"+   ".aam"       -> "application/x-authorware-map"+   ".aas"       -> "application/x-authorware-seg"+   ".abc"       -> "text/vnd.abc"+   ".acgi"      -> "text/html"+   ".afl"       -> "video/animaflex"+   ".ai"        -> "application/postscript"+   ".aif"       -> "audio/aiff"+   ".aifc"      -> "audio/aiff"+   ".aiff"      -> "audio/aiff"+   ".aim"       -> "application/x-aim"+   ".aip"       -> "text/x-audiosoft-intra"+   ".ani"       -> "application/x-navi-animation"+   ".aos"       -> "application/x-nokia-9000-communicator-add-on-software"+   ".aps"       -> "application/mime"+   ".arc"       -> "application/octet-stream"+   ".arj"       -> "application/arj"+   ".art"       -> "image/x-jg"+   ".asf"       -> "video/x-ms-asf"+   ".asm"       -> "text/x-asm"+   ".asp"       -> "text/asp"+   ".asx"       -> "application/x-mplayer2"+   ".au"        -> "audio/basic"+   ".avi"       -> "application/x-troff-msvideo"+   ".avs"       -> "video/avs-video"+   ".bcpio"     -> "application/x-bcpio"+   ".bin"       -> "application/mac-binary"+   ".bm"        -> "image/bmp"+   ".bmp"       -> "image/bmp"+   ".boo"       -> "application/book"+   ".book"      -> "application/book"+   ".boz"       -> "application/x-bzip2"+   ".bsh"       -> "application/x-bsh"+   ".bz"        -> "application/x-bzip"+   ".bz2"       -> "application/x-bzip2"+   ".c"         -> "text/plain"+   ".c++"       -> "text/plain"+   ".cat"       -> "application/vnd.ms-pki.seccat"+   ".cc"        -> "text/plain"+   ".ccad"      -> "application/clariscad"+   ".cco"       -> "application/x-cocoa"+   ".cdf"       -> "application/cdf"+   ".cer"       -> "application/pkix-cert"+   ".cha"       -> "application/x-chat"+   ".chat"      -> "application/x-chat"+   ".class"     -> "application/java"+   ".com"       -> "application/octet-stream"+   ".conf"      -> "text/plain"+   ".cpio"      -> "application/x-cpio"+   ".cpp"       -> "text/x-c"+   ".cpt"       -> "application/mac-compactpro"+   ".crl"       -> "application/pkcs-crl"+   ".crt"       -> "application/pkix-cert"+   ".csh"       -> "application/x-csh"+   ".css"       -> "application/x-pointplus"+   ".cxx"       -> "text/plain"+   ".dcr"       -> "application/x-director"+   ".deepv"     -> "application/x-deepv"+   ".def"       -> "text/plain"+   ".der"       -> "application/x-x509-ca-cert"+   ".dif"       -> "video/x-dv"+   ".dir"       -> "application/x-director"+   ".dl"        -> "video/dl"+   ".doc"       -> "application/msword"+   ".dot"       -> "application/msword"+   ".dp"        -> "application/commonground"+   ".drw"       -> "application/drafting"+   ".dump"      -> "application/octet-stream"+   ".dv"        -> "video/x-dv"+   ".dvi"       -> "application/x-dvi"+   ".dwf"       -> "drawing/x-dwf (old)"+   ".dwg"       -> "application/acad"+   ".dxf"       -> "application/dxf"+   ".dxr"       -> "application/x-director"+   ".el"        -> "text/x-script.elisp"+   ".elc"       -> "application/x-bytecode.elisp (compiled elisp)"+   ".env"       -> "application/x-envoy"+   ".eps"       -> "application/postscript"+   ".es"        -> "application/x-esrehber"+   ".etx"       -> "text/x-setext"+   ".evy"       -> "application/envoy"+   ".exe"       -> "application/octet-stream"+   ".f"         -> "text/plain"+   ".f77"       -> "text/x-fortran"+   ".f90"       -> "text/plain"+   ".fdf"       -> "application/vnd.fdf"+   ".fif"       -> "application/fractals"+   ".fli"       -> "video/fli"+   ".flo"       -> "image/florian"+   ".flx"       -> "text/vnd.fmi.flexstor"+   ".fmf"       -> "video/x-atomic3d-feature"+   ".for"       -> "text/plain"+   ".fpx"       -> "image/vnd.fpx"+   ".frl"       -> "application/freeloader"+   ".funk"      -> "audio/make"+   ".g"         -> "text/plain"+   ".g3"        -> "image/g3fax"+   ".gif"       -> "image/gif"+   ".gl"        -> "video/gl"+   ".gsd"       -> "audio/x-gsm"+   ".gsm"       -> "audio/x-gsm"+   ".gsp"       -> "application/x-gsp"+   ".gss"       -> "application/x-gss"+   ".gtar"      -> "application/x-gtar"+   ".gz"        -> "application/x-compressed"+   ".gzip"      -> "application/x-gzip"+   ".h"         -> "text/plain"+   ".hdf"       -> "application/x-hdf"+   ".help"      -> "application/x-helpfile"+   ".hgl"       -> "application/vnd.hp-hpgl"+   ".hh"        -> "text/plain"+   ".hlb"       -> "text/x-script"+   ".hlp"       -> "application/hlp"+   ".hpg"       -> "application/vnd.hp-hpgl"+   ".hpgl"      -> "application/vnd.hp-hpgl"+   ".hqx"       -> "application/binhex"+   ".hs"        -> "text/x-haskell"+   ".hta"       -> "application/hta"+   ".htc"       -> "text/x-component"+   ".htm"       -> "text/html"+   ".html"      -> "text/html"+   ".htmls"     -> "text/html"+   ".htt"       -> "text/webviewhtml"+   ".htx"       -> "text/html"+   ".ice"       -> "x-conference/x-cooltalk"+   ".ico"       -> "image/x-icon"+   ".idc"       -> "text/plain"+   ".ief"       -> "image/ief"+   ".iefs"      -> "image/ief"+   ".iges"      -> "application/iges"+   ".igs"       -> "application/iges"+   ".ima"       -> "application/x-ima"+   ".imap"      -> "application/x-httpd-imap"+   ".inf"       -> "application/inf"+   ".ins"       -> "application/x-internett-signup"+   ".ip"        -> "application/x-ip2"+   ".isu"       -> "video/x-isvideo"+   ".it"        -> "audio/it"+   ".iv"        -> "application/x-inventor"+   ".ivr"       -> "i-world/i-vrml"+   ".ivy"       -> "application/x-livescreen"+   ".jam"       -> "audio/x-jam"+   ".jav"       -> "text/plain"+   ".java"      -> "text/plain"+   ".jcm"       -> "application/x-java-commerce"+   ".jfif"      -> "image/jpeg"+   ".jfif-tbnl" -> "image/jpeg"+   ".jpe"       -> "image/jpeg"+   ".jpeg"      -> "image/jpeg"+   ".jpg"       -> "image/jpeg"+   ".jps"       -> "image/x-jps"+   ".js"        -> "application/x-javascript"+   ".jut"       -> "image/jutvision"+   ".kar"       -> "audio/midi"+   ".ksh"       -> "application/x-ksh"+   ".la"        -> "audio/nspaudio"+   ".lam"       -> "audio/x-liveaudio"+   ".latex"     -> "application/x-latex"+   ".lha"       -> "application/lha"+   ".lhx"       -> "application/octet-stream"+   ".list"      -> "text/plain"+   ".lma"       -> "audio/nspaudio"+   ".log"       -> "text/plain"+   ".lsp"       -> "application/x-lisp"+   ".lst"       -> "text/plain"+   ".lsx"       -> "text/x-la-asf"+   ".ltx"       -> "application/x-latex"+   ".lzh"       -> "application/octet-stream"+   ".lzx"       -> "application/lzx"+   ".m"         -> "text/plain"+   ".m1v"       -> "video/mpeg"+   ".m2a"       -> "audio/mpeg"+   ".m2v"       -> "video/mpeg"+   ".m3u"       -> "audio/x-mpequrl"+   ".man"       -> "application/x-troff-man"+   ".map"       -> "application/x-navimap"+   ".mar"       -> "text/plain"+   ".mbd"       -> "application/mbedlet"+   ".mc$"       -> "application/x-magic-cap-package-1.0"+   ".mcd"       -> "application/mcad"+   ".mcf"       -> "image/vasa"+   ".mcp"       -> "application/netmc"+   ".me"        -> "application/x-troff-me"+   ".mht"       -> "message/rfc822"+   ".mhtml"     -> "message/rfc822"+   ".mid"       -> "application/x-midi"+   ".midi"      -> "application/x-midi"+   ".mif"       -> "application/x-frame"+   ".mime"      -> "message/rfc822"+   ".mjf"       -> "audio/x-vnd.audioexplosion.mjuicemediafile"+   ".mjpg"      -> "video/x-motion-jpeg"+   ".mm"        -> "application/base64"+   ".mme"       -> "application/base64"+   ".mod"       -> "audio/mod"+   ".moov"      -> "video/quicktime"+   ".mov"       -> "video/quicktime"+   ".movie"     -> "video/x-sgi-movie"+   ".mp2"       -> "audio/mpeg"+   ".mp3"       -> "audio/mpeg3"+   ".mpa"       -> "audio/mpeg"+   ".mpc"       -> "application/x-project"+   ".mpe"       -> "video/mpeg"+   ".mpeg"      -> "video/mpeg"+   ".mpg"       -> "audio/mpeg"+   ".mpga"      -> "audio/mpeg"+   ".mpp"       -> "application/vnd.ms-project"+   ".mpt"       -> "application/x-project"+   ".mpv"       -> "application/x-project"+   ".mpx"       -> "application/x-project"+   ".mrc"       -> "application/marc"+   ".ms"        -> "application/x-troff-ms"+   ".mv"        -> "video/x-sgi-movie"+   ".my"        -> "audio/make"+   ".mzz"       -> "application/x-vnd.audioexplosion.mzz"+   ".nap"       -> "image/naplps"+   ".naplps"    -> "image/naplps"+   ".nc"        -> "application/x-netcdf"+   ".ncm"       -> "application/vnd.nokia.configuration-message"+   ".nif"       -> "image/x-niff"+   ".niff"      -> "image/x-niff"+   ".nix"       -> "application/x-mix-transfer"+   ".nsc"       -> "application/x-conference"+   ".nvd"       -> "application/x-navidoc"+   ".o"         -> "application/octet-stream"+   ".oda"       -> "application/oda"+   ".omc"       -> "application/x-omc"+   ".omcd"      -> "application/x-omcdatamaker"+   ".omcr"      -> "application/x-omcregerator"+   ".p"         -> "text/x-pascal"+   ".p10"       -> "application/pkcs10"+   ".p12"       -> "application/pkcs-12"+   ".p7a"       -> "application/x-pkcs7-signature"+   ".p7c"       -> "application/pkcs7-mime"+   ".p7m"       -> "application/pkcs7-mime"+   ".p7r"       -> "application/x-pkcs7-certreqresp"+   ".p7s"       -> "application/pkcs7-signature"+   ".part"      -> "application/pro_eng"+   ".pas"       -> "text/pascal"+   ".pbm"       -> "image/x-portable-bitmap"+   ".pcl"       -> "application/vnd.hp-pcl"+   ".pct"       -> "image/x-pict"+   ".pcx"       -> "image/x-pcx"+   ".pdb"       -> "chemical/x-pdb"+   ".pdf"       -> "application/pdf"+   ".pfunk"     -> "audio/make"+   ".pgm"       -> "image/x-portable-graymap"+   ".pic"       -> "image/pict"+   ".pict"      -> "image/pict"+   ".pkg"       -> "application/x-newton-compatible-pkg"+   ".pko"       -> "application/vnd.ms-pki.pko"+   ".pl"        -> "text/plain"+   ".plx"       -> "application/x-pixclscript"+   ".pm"        -> "image/x-xpixmap"+   ".pm4"       -> "application/x-pagemaker"+   ".pm5"       -> "application/x-pagemaker"+   ".png"       -> "image/png"+   ".pnm"       -> "application/x-portable-anymap"+   ".pot"       -> "application/mspowerpoint"+   ".pov"       -> "model/x-pov"+   ".ppa"       -> "application/vnd.ms-powerpoint"+   ".ppm"       -> "image/x-portable-pixmap"+   ".pps"       -> "application/mspowerpoint"+   ".ppt"       -> "application/mspowerpoint"+   ".ppz"       -> "application/mspowerpoint"+   ".pre"       -> "application/x-freelance"+   ".prt"       -> "application/pro_eng"+   ".ps"        -> "application/postscript"+   ".psd"       -> "application/octet-stream"+   ".pvu"       -> "paleovu/x-pv"+   ".pwz"       -> "application/vnd.ms-powerpoint"+   ".py"        -> "text/x-script.phyton"+   ".pyc"       -> "applicaiton/x-bytecode.python"+   ".qcp"       -> "audio/vnd.qcelp"+   ".qd3"       -> "x-world/x-3dmf"+   ".qd3d"      -> "x-world/x-3dmf"+   ".qif"       -> "image/x-quicktime"+   ".qt"        -> "video/quicktime"+   ".qtc"       -> "video/x-qtc"+   ".qti"       -> "image/x-quicktime"+   ".qtif"      -> "image/x-quicktime"+   ".ra"        -> "audio/x-pn-realaudio"+   ".ram"       -> "audio/x-pn-realaudio"+   ".ras"       -> "application/x-cmu-raster"+   ".rast"      -> "image/cmu-raster"+   ".rexx"      -> "text/x-script.rexx"+   ".rf"        -> "image/vnd.rn-realflash"+   ".rgb"       -> "image/x-rgb"+   ".rm"        -> "application/vnd.rn-realmedia"+   ".rmi"       -> "audio/mid"+   ".rmm"       -> "audio/x-pn-realaudio"+   ".rmp"       -> "audio/x-pn-realaudio"+   ".rng"       -> "application/ringing-tones"+   ".rnx"       -> "application/vnd.rn-realplayer"+   ".roff"      -> "application/x-troff"+   ".rp"        -> "image/vnd.rn-realpix"+   ".rpm"       -> "audio/x-pn-realaudio-plugin"+   ".rt"        -> "text/richtext"+   ".rtf"       -> "application/rtf"+   ".rtx"       -> "application/rtf"+   ".rv"        -> "video/vnd.rn-realvideo"+   ".s"         -> "text/x-asm"+   ".s3m"       -> "audio/s3m"+   ".saveme"    -> "application/octet-stream"+   ".sbk"       -> "application/x-tbook"+   ".scm"       -> "application/x-lotusscreencam"+   ".sdml"      -> "text/plain"+   ".sdp"       -> "application/sdp"+   ".sdr"       -> "application/sounder"+   ".sea"       -> "application/sea"+   ".set"       -> "application/set"+   ".sgm"       -> "text/sgml"+   ".sgml"      -> "text/sgml"+   ".sh"        -> "application/x-bsh"+   ".shar"      -> "application/x-bsh"+   ".shtml"     -> "text/html"+   ".sid"       -> "audio/x-psid"+   ".sit"       -> "application/x-sit"+   ".skd"       -> "application/x-koan"+   ".skm"       -> "application/x-koan"+   ".skp"       -> "application/x-koan"+   ".skt"       -> "application/x-koan"+   ".sl"        -> "application/x-seelogo"+   ".smi"       -> "application/smil"+   ".smil"      -> "application/smil"+   ".snd"       -> "audio/basic"+   ".sol"       -> "application/solids"+   ".spc"       -> "application/x-pkcs7-certificates"+   ".spl"       -> "application/futuresplash"+   ".spr"       -> "application/x-sprite"+   ".sprite"    -> "application/x-sprite"+   ".src"       -> "application/x-wais-source"+   ".ssi"       -> "text/x-server-parsed-html"+   ".ssm"       -> "application/streamingmedia"+   ".sst"       -> "application/vnd.ms-pki.certstore"+   ".step"      -> "application/step"+   ".stl"       -> "application/sla"+   ".stp"       -> "application/step"+   ".sv4cpio"   -> "application/x-sv4cpio"+   ".sv4crc"    -> "application/x-sv4crc"+   ".svf"       -> "image/vnd.dwg"+   ".svr"       -> "application/x-world"+   ".swf"       -> "application/x-shockwave-flash"+   ".t"         -> "application/x-troff"+   ".talk"      -> "text/x-speech"+   ".tar"       -> "application/x-tar"+   ".tbk"       -> "application/toolbook"+   ".tcl"       -> "application/x-tcl"+   ".tcsh"      -> "text/x-script.tcsh"+   ".tex"       -> "application/x-tex"+   ".texi"      -> "application/x-texinfo"+   ".texinfo"   -> "application/x-texinfo"+   ".text"      -> "application/plain"+   ".tgz"       -> "application/gnutar"+   ".tif"       -> "image/tiff"+   ".tiff"      -> "image/tiff"+   ".tr"        -> "application/x-troff"+   ".tsi"       -> "audio/tsp-audio"+   ".tsp"       -> "application/dsptype"+   ".tsv"       -> "text/tab-separated-values"+   ".turbot"    -> "image/florian"+   ".txt"       -> "text/plain"+   ".uil"       -> "text/x-uil"+   ".uni"       -> "text/uri-list"+   ".unis"      -> "text/uri-list"+   ".unv"       -> "application/i-deas"+   ".uri"       -> "text/uri-list"+   ".uris"      -> "text/uri-list"+   ".ustar"     -> "application/x-ustar"+   ".uu"        -> "application/octet-stream"+   ".uue"       -> "text/x-uuencode"+   ".vcd"       -> "application/x-cdlink"+   ".vcs"       -> "text/x-vcalendar"+   ".vda"       -> "application/vda"+   ".vdo"       -> "video/vdo"+   ".vew"       -> "application/groupwise"+   ".viv"       -> "video/vivo"+   ".vivo"      -> "video/vivo"+   ".vmd"       -> "application/vocaltec-media-desc"+   ".vmf"       -> "application/vocaltec-media-file"+   ".voc"       -> "audio/voc"+   ".vos"       -> "video/vosaic"+   ".vox"       -> "audio/voxware"+   ".vqe"       -> "audio/x-twinvq-plugin"+   ".vqf"       -> "audio/x-twinvq"+   ".vql"       -> "audio/x-twinvq-plugin"+   ".vrml"      -> "application/x-vrml"+   ".vrt"       -> "x-world/x-vrt"+   ".vsd"       -> "application/x-visio"+   ".vst"       -> "application/x-visio"+   ".vsw"       -> "application/x-visio"+   ".w60"       -> "application/wordperfect6.0"+   ".w61"       -> "application/wordperfect6.1"+   ".w6w"       -> "application/msword"+   ".wav"       -> "audio/wav"+   ".wb1"       -> "application/x-qpro"+   ".wbmp"      -> "image/vnd.wap.wbmp"+   ".web"       -> "application/vnd.xara"+   ".wiz"       -> "application/msword"+   ".wk1"       -> "application/x-123"+   ".wmf"       -> "windows/metafile"+   ".wml"       -> "text/vnd.wap.wml"+   ".wmlc"      -> "application/vnd.wap.wmlc"+   ".wmls"      -> "text/vnd.wap.wmlscript"+   ".wmlsc"     -> "application/vnd.wap.wmlscriptc"+   ".word"      -> "application/msword"+   ".wp"        -> "application/wordperfect"+   ".wp5"       -> "application/wordperfect"+   ".wp6"       -> "application/wordperfect"+   ".wpd"       -> "application/wordperfect"+   ".wq1"       -> "application/x-lotus"+   ".wri"       -> "application/mswrite"+   ".wrl"       -> "application/x-world"+   ".wrz"       -> "model/vrml"+   ".wsc"       -> "text/scriplet"+   ".wsrc"      -> "application/x-wais-source"+   ".wtk"       -> "application/x-wintalk"+   ".xbm"       -> "image/x-xbitmap"+   ".xdr"       -> "video/x-amt-demorun"+   ".xgz"       -> "xgl/drawing"+   ".xif"       -> "image/vnd.xiff"+   ".xl"        -> "application/excel"+   ".xla"       -> "application/excel"+   ".xlb"       -> "application/excel"+   ".xlc"       -> "application/excel"+   ".xld"       -> "application/excel"+   ".xlk"       -> "application/excel"+   ".xll"       -> "application/excel"+   ".xlm"       -> "application/excel"+   ".xls"       -> "application/excel"+   ".xlt"       -> "application/excel"+   ".xlv"       -> "application/excel"+   ".xlw"       -> "application/excel"+   ".xm"        -> "audio/xm"+   ".xml"       -> "application/xml"+   ".xmz"       -> "xgl/movie"+   ".xpix"      -> "application/x-vnd.ls-xpix"+   ".xpm"       -> "image/x-xpixmap"+   ".x-png"     -> "image/png"+   ".xsr"       -> "video/x-amt-showrun"+   ".xwd"       -> "image/x-xwd"+   ".xyz"       -> "chemical/x-pdb"+   ".z"         -> "application/x-compress"+   ".zip"       -> "application/x-compressed"+   ".zoo"       -> "application/octet-stream"+   ".zsh"       -> "text/x-script.zsh"+   _            -> "application/octet-stream"
README.org view
@@ -26,7 +26,7 @@ #+BEGIN_SRC haskell >>> :set -XOverloadedStrings >>> :module Network.Mail.Mime Network.Mail.Client.Gmail->>> sendGmail "alice" "password" (Address (Just "Alice") "alice@gmail.com") [Address (Just "Bob") "bob@example.com"] [] [] "Excel Spreadsheet" "Hi Bob,\n\nThe Excel spreadsheet is attached.\n\nRegards,\n\nAlice" ["spreadsheet.xls"] Nothing+>>> sendGmail "alice" "password" (Address (Just "Alice") "alice@gmail.com") [Address (Just "Bob") "bob@example.com"] [] [] "Excel Spreadsheet" "Hi Bob,\n\nThe Excel spreadsheet is attached.\n\nRegards,\n\nAlice" ["Spreadsheet.xls"] #+END_SRC  ** Resources
smtps-gmail.cabal view
@@ -1,5 +1,5 @@ Name:               smtps-gmail-Version:            1.1.1+Version:            1.2.0 License:            BSD3 License-File:       LICENSE Copyright:          Copyright (c) 2014, Enzo Haussecker. All rights reserved.