initial commit
This commit is contained in:
		
							
								
								
									
										33
									
								
								lib/mailex.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								lib/mailex.ex
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,33 @@
 | 
			
		||||
defmodule Mailex do
 | 
			
		||||
 | 
			
		||||
  @config_defaults [
 | 
			
		||||
    relay:    nil,
 | 
			
		||||
    username: "",
 | 
			
		||||
    password: "",
 | 
			
		||||
    port:     25,
 | 
			
		||||
    ssl:      false,
 | 
			
		||||
    tls:      :never,
 | 
			
		||||
    auth:     :always
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
  def deliver(email, config \\ []) do
 | 
			
		||||
    config = Keyword.merge(@config_defaults, config)
 | 
			
		||||
 | 
			
		||||
    message = email |> Mailex.Render.render
 | 
			
		||||
    from    = email.from |> Mailex.Address.envelope_format
 | 
			
		||||
    to      = email.to |> Mailex.Address.envelope_format
 | 
			
		||||
 | 
			
		||||
    if Keyword.get(config, :relay) do
 | 
			
		||||
      envelope = { from, to, message }
 | 
			
		||||
      case :gen_smtp_client.send_blocking(envelope, config) do
 | 
			
		||||
        { :error, msg } -> { :error, msg }
 | 
			
		||||
                    msg -> { :ok, msg }
 | 
			
		||||
      end
 | 
			
		||||
    else
 | 
			
		||||
      IO.puts "\n\n[[[ Mailex ]]]\n\nFROM: #{from}\nTO: #{to}\n"
 | 
			
		||||
      IO.puts "RAW START -------\n#{message}\nRAW END -------"
 | 
			
		||||
      {:ok, "dumped to console"}
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										32
									
								
								lib/mailex/address.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								lib/mailex/address.ex
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,32 @@
 | 
			
		||||
defmodule Mailex.Address do
 | 
			
		||||
  defstruct name: nil, address: nil
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def rfc_822_format(emails) when is_list(emails), do:
 | 
			
		||||
    emails |> Enum.map(&rfc_822_format(&1))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def rfc_822_format(email) when is_map(email) do
 | 
			
		||||
    if email.name do
 | 
			
		||||
      "#{email.name} <#{email.address}>"
 | 
			
		||||
    else
 | 
			
		||||
      name = email.address |>
 | 
			
		||||
        String.split("@") |>
 | 
			
		||||
        List.first |>
 | 
			
		||||
        String.split(~r/([^\w\s]|_)/) |>
 | 
			
		||||
        Enum.map(&String.capitalize/1) |>
 | 
			
		||||
        Enum.join " "
 | 
			
		||||
      "#{name} <#{email.address}>"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def envelope_format(emails) when is_list(emails), do:
 | 
			
		||||
    emails |> Enum.map(&envelope_format(&1))
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def envelope_format(email) when is_map(email), do:
 | 
			
		||||
    "<#{email.address}>"
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										694
									
								
								lib/mailex/attachment.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										694
									
								
								lib/mailex/attachment.ex
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,694 @@
 | 
			
		||||
defmodule Mailex.Attachment do
 | 
			
		||||
 | 
			
		||||
  defstruct filename: nil, type: nil, data: nil
 | 
			
		||||
 | 
			
		||||
  @mime_types [
 | 
			
		||||
    { ".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" },
 | 
			
		||||
    { ".aif", "audio", "x-aiff" },
 | 
			
		||||
    { ".aifc", "audio", "aiff" },
 | 
			
		||||
    { ".aifc", "audio", "x-aiff" },
 | 
			
		||||
    { ".aiff", "audio", "aiff" },
 | 
			
		||||
    { ".aiff", "audio", "x-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" },
 | 
			
		||||
    { ".arj", "application", "octet-stream" },
 | 
			
		||||
    { ".art", "image", "x-jg" },
 | 
			
		||||
    { ".asf", "video", "x-ms-asf" },
 | 
			
		||||
    { ".asm", "text", "x-asm" },
 | 
			
		||||
    { ".asp", "text", "asp" },
 | 
			
		||||
    { ".asx", "application", "x-mplayer2" },
 | 
			
		||||
    { ".asx", "video", "x-ms-asf" },
 | 
			
		||||
    { ".asx", "video", "x-ms-asf-plugin" },
 | 
			
		||||
    { ".au", "audio", "basic" },
 | 
			
		||||
    { ".au", "audio", "x-au" },
 | 
			
		||||
    { ".avi", "application", "x-troff-msvideo" },
 | 
			
		||||
    { ".avi", "video", "avi" },
 | 
			
		||||
    { ".avi", "video", "msvideo" },
 | 
			
		||||
    { ".avi", "video", "x-msvideo" },
 | 
			
		||||
    { ".avs", "video", "avs-video" },
 | 
			
		||||
    { ".bcpio", "application", "x-bcpio" },
 | 
			
		||||
    { ".bin", "application", "mac-binary" },
 | 
			
		||||
    { ".bin", "application", "macbinary" },
 | 
			
		||||
    { ".bin", "application", "octet-stream" },
 | 
			
		||||
    { ".bin", "application", "x-binary" },
 | 
			
		||||
    { ".bin", "application", "x-macbinary" },
 | 
			
		||||
    { ".bm", "image", "bmp" },
 | 
			
		||||
    { ".bmp", "image", "bmp" },
 | 
			
		||||
    { ".bmp", "image", "x-windows-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", "x-c" },
 | 
			
		||||
    { ".c++", "text", "plain" },
 | 
			
		||||
    { ".cat", "application", "vnd.ms-pki.seccat" },
 | 
			
		||||
    { ".cc", "text", "plain" },
 | 
			
		||||
    { ".cc", "text", "x-c" },
 | 
			
		||||
    { ".ccad", "application", "clariscad" },
 | 
			
		||||
    { ".cco", "application", "x-cocoa" },
 | 
			
		||||
    { ".cdf", "application", "cdf" },
 | 
			
		||||
    { ".cdf", "application", "x-cdf" },
 | 
			
		||||
    { ".cdf", "application", "x-netcdf" },
 | 
			
		||||
    { ".cer", "application", "pkix-cert" },
 | 
			
		||||
    { ".cer", "application", "x-x509-ca-cert" },
 | 
			
		||||
    { ".cha", "application", "x-chat" },
 | 
			
		||||
    { ".chat", "application", "x-chat" },
 | 
			
		||||
    { ".class", "application", "java" },
 | 
			
		||||
    { ".class", "application", "java-byte-code" },
 | 
			
		||||
    { ".class", "application", "x-java-class" },
 | 
			
		||||
    { ".com", "application", "octet-stream" },
 | 
			
		||||
    { ".com", "text", "plain" },
 | 
			
		||||
    { ".conf", "text", "plain" },
 | 
			
		||||
    { ".cpio", "application", "x-cpio" },
 | 
			
		||||
    { ".cpp", "text", "x-c" },
 | 
			
		||||
    { ".cpt", "application", "mac-compactpro" },
 | 
			
		||||
    { ".cpt", "application", "x-compactpro" },
 | 
			
		||||
    { ".cpt", "application", "x-cpt" },
 | 
			
		||||
    { ".crl", "application", "pkcs-crl" },
 | 
			
		||||
    { ".crl", "application", "pkix-crl" },
 | 
			
		||||
    { ".crt", "application", "pkix-cert" },
 | 
			
		||||
    { ".crt", "application", "x-x509-ca-cert" },
 | 
			
		||||
    { ".crt", "application", "x-x509-user-cert" },
 | 
			
		||||
    { ".csh", "application", "x-csh" },
 | 
			
		||||
    { ".csh", "text", "x-script.csh" },
 | 
			
		||||
    { ".css", "application", "x-pointplus" },
 | 
			
		||||
    { ".css", "text", "css" },
 | 
			
		||||
    { ".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" },
 | 
			
		||||
    { ".dl", "video", "x-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)" },
 | 
			
		||||
    { ".dwf", "model", "vnd.dwf" },
 | 
			
		||||
    { ".dwg", "application", "acad" },
 | 
			
		||||
    { ".dwg", "image", "vnd.dwg" },
 | 
			
		||||
    { ".dwg", "image", "x-dwg" },
 | 
			
		||||
    { ".dxf", "application", "dxf" },
 | 
			
		||||
    { ".dxf", "image", "vnd.dwg" },
 | 
			
		||||
    { ".dxf", "image", "x-dwg" },
 | 
			
		||||
    { ".dxr", "application", "x-director" },
 | 
			
		||||
    { ".el", "text", "x-script.elisp" },
 | 
			
		||||
    { ".elc", "application", "x-bytecode.elisp, (compiled, elisp)" },
 | 
			
		||||
    { ".elc", "application", "x-elc" },
 | 
			
		||||
    { ".env", "application", "x-envoy" },
 | 
			
		||||
    { ".eps", "application", "postscript" },
 | 
			
		||||
    { ".es", "application", "x-esrehber" },
 | 
			
		||||
    { ".etx", "text", "x-setext" },
 | 
			
		||||
    { ".evy", "application", "envoy" },
 | 
			
		||||
    { ".evy", "application", "x-envoy" },
 | 
			
		||||
    { ".exe", "application", "octet-stream" },
 | 
			
		||||
    { ".f", "text", "plain" },
 | 
			
		||||
    { ".f", "text", "x-fortran" },
 | 
			
		||||
    { ".f77", "text", "x-fortran" },
 | 
			
		||||
    { ".f90", "text", "plain" },
 | 
			
		||||
    { ".f90", "text", "x-fortran" },
 | 
			
		||||
    { ".fdf", "application", "vnd.fdf" },
 | 
			
		||||
    { ".fif", "application", "fractals" },
 | 
			
		||||
    { ".fif", "image", "fif" },
 | 
			
		||||
    { ".fli", "video", "fli" },
 | 
			
		||||
    { ".fli", "video", "x-fli" },
 | 
			
		||||
    { ".flo", "image", "florian" },
 | 
			
		||||
    { ".flx", "text", "vnd.fmi.flexstor" },
 | 
			
		||||
    { ".fmf", "video", "x-atomic3d-feature" },
 | 
			
		||||
    { ".for", "text", "plain" },
 | 
			
		||||
    { ".for", "text", "x-fortran" },
 | 
			
		||||
    { ".fpx", "image", "vnd.fpx" },
 | 
			
		||||
    { ".fpx", "image", "vnd.net-fpx" },
 | 
			
		||||
    { ".frl", "application", "freeloader" },
 | 
			
		||||
    { ".funk", "audio", "make" },
 | 
			
		||||
    { ".g", "text", "plain" },
 | 
			
		||||
    { ".g3", "image", "g3fax" },
 | 
			
		||||
    { ".gif", "image", "gif" },
 | 
			
		||||
    { ".gl", "video", "gl" },
 | 
			
		||||
    { ".gl", "video", "x-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" },
 | 
			
		||||
    { ".gz", "application", "x-gzip" },
 | 
			
		||||
    { ".gzip", "application", "x-gzip" },
 | 
			
		||||
    { ".gzip", "multipart", "x-gzip" },
 | 
			
		||||
    { ".h", "text", "plain" },
 | 
			
		||||
    { ".h", "text", "x-h" },
 | 
			
		||||
    { ".hdf", "application", "x-hdf" },
 | 
			
		||||
    { ".help", "application", "x-helpfile" },
 | 
			
		||||
    { ".hgl", "application", "vnd.hp-hpgl" },
 | 
			
		||||
    { ".hh", "text", "plain" },
 | 
			
		||||
    { ".hh", "text", "x-h" },
 | 
			
		||||
    { ".hlb", "text", "x-script" },
 | 
			
		||||
    { ".hlp", "application", "hlp" },
 | 
			
		||||
    { ".hlp", "application", "x-helpfile" },
 | 
			
		||||
    { ".hlp", "application", "x-winhelp" },
 | 
			
		||||
    { ".hpg", "application", "vnd.hp-hpgl" },
 | 
			
		||||
    { ".hpgl", "application", "vnd.hp-hpgl" },
 | 
			
		||||
    { ".hqx", "application", "binhex" },
 | 
			
		||||
    { ".hqx", "application", "binhex4" },
 | 
			
		||||
    { ".hqx", "application", "mac-binhex" },
 | 
			
		||||
    { ".hqx", "application", "mac-binhex40" },
 | 
			
		||||
    { ".hqx", "application", "x-binhex40" },
 | 
			
		||||
    { ".hqx", "application", "x-mac-binhex40" },
 | 
			
		||||
    { ".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" },
 | 
			
		||||
    { ".iges", "model", "iges" },
 | 
			
		||||
    { ".igs", "application", "iges" },
 | 
			
		||||
    { ".igs", "model", "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" },
 | 
			
		||||
    { ".jav", "text", "x-java-source" },
 | 
			
		||||
    { ".java", "text", "plain" },
 | 
			
		||||
    { ".java", "text", "x-java-source" },
 | 
			
		||||
    { ".jcm", "application", "x-java-commerce" },
 | 
			
		||||
    { ".jfif", "image", "jpeg" },
 | 
			
		||||
    { ".jfif", "image", "pjpeg" },
 | 
			
		||||
    { ".jfif-tbnl", "image", "jpeg" },
 | 
			
		||||
    { ".jpe", "image", "jpeg" },
 | 
			
		||||
    { ".jpe", "image", "pjpeg" },
 | 
			
		||||
    { ".jpeg", "image", "jpeg" },
 | 
			
		||||
    { ".jpeg", "image", "pjpeg" },
 | 
			
		||||
    { ".jpg", "image", "jpeg" },
 | 
			
		||||
    { ".jpg", "image", "pjpeg" },
 | 
			
		||||
    { ".jps", "image", "x-jps" },
 | 
			
		||||
    { ".js", "application", "x-javascript" },
 | 
			
		||||
    { ".js", "application", "javascript" },
 | 
			
		||||
    { ".js", "application", "ecmascript" },
 | 
			
		||||
    { ".js", "text", "javascript" },
 | 
			
		||||
    { ".js", "text", "ecmascript" },
 | 
			
		||||
    { ".jut", "image", "jutvision" },
 | 
			
		||||
    { ".kar", "audio", "midi" },
 | 
			
		||||
    { ".kar", "music", "x-karaoke" },
 | 
			
		||||
    { ".ksh", "application", "x-ksh" },
 | 
			
		||||
    { ".ksh", "text", "x-script.ksh" },
 | 
			
		||||
    { ".la", "audio", "nspaudio" },
 | 
			
		||||
    { ".la", "audio", "x-nspaudio" },
 | 
			
		||||
    { ".lam", "audio", "x-liveaudio" },
 | 
			
		||||
    { ".latex", "application", "x-latex" },
 | 
			
		||||
    { ".lha", "application", "lha" },
 | 
			
		||||
    { ".lha", "application", "octet-stream" },
 | 
			
		||||
    { ".lha", "application", "x-lha" },
 | 
			
		||||
    { ".lhx", "application", "octet-stream" },
 | 
			
		||||
    { ".list", "text", "plain" },
 | 
			
		||||
    { ".lma", "audio", "nspaudio" },
 | 
			
		||||
    { ".lma", "audio", "x-nspaudio" },
 | 
			
		||||
    { ".log", "text", "plain" },
 | 
			
		||||
    { ".lsp", "application", "x-lisp" },
 | 
			
		||||
    { ".lsp", "text", "x-script.lisp" },
 | 
			
		||||
    { ".lst", "text", "plain" },
 | 
			
		||||
    { ".lsx", "text", "x-la-asf" },
 | 
			
		||||
    { ".ltx", "application", "x-latex" },
 | 
			
		||||
    { ".lzh", "application", "octet-stream" },
 | 
			
		||||
    { ".lzh", "application", "x-lzh" },
 | 
			
		||||
    { ".lzx", "application", "lzx" },
 | 
			
		||||
    { ".lzx", "application", "octet-stream" },
 | 
			
		||||
    { ".lzx", "application", "x-lzx" },
 | 
			
		||||
    { ".m", "text", "plain" },
 | 
			
		||||
    { ".m", "text", "x-m" },
 | 
			
		||||
    { ".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" },
 | 
			
		||||
    { ".mcd", "application", "x-mathcad" },
 | 
			
		||||
    { ".mcf", "image", "vasa" },
 | 
			
		||||
    { ".mcf", "text", "mcf" },
 | 
			
		||||
    { ".mcp", "application", "netmc" },
 | 
			
		||||
    { ".me", "application", "x-troff-me" },
 | 
			
		||||
    { ".mht", "message", "rfc822" },
 | 
			
		||||
    { ".mhtml", "message", "rfc822" },
 | 
			
		||||
    { ".mid", "application", "x-midi" },
 | 
			
		||||
    { ".mid", "audio", "midi" },
 | 
			
		||||
    { ".mid", "audio", "x-mid" },
 | 
			
		||||
    { ".mid", "audio", "x-midi" },
 | 
			
		||||
    { ".mid", "music", "crescendo" },
 | 
			
		||||
    { ".mid", "x-music", "x-midi" },
 | 
			
		||||
    { ".midi", "application", "x-midi" },
 | 
			
		||||
    { ".midi", "audio", "midi" },
 | 
			
		||||
    { ".midi", "audio", "x-mid" },
 | 
			
		||||
    { ".midi", "audio", "x-midi" },
 | 
			
		||||
    { ".midi", "music", "crescendo" },
 | 
			
		||||
    { ".midi", "x-music", "x-midi" },
 | 
			
		||||
    { ".mif", "application", "x-frame" },
 | 
			
		||||
    { ".mif", "application", "x-mif" },
 | 
			
		||||
    { ".mime", "message", "rfc822" },
 | 
			
		||||
    { ".mime", "www", "mime" },
 | 
			
		||||
    { ".mjf", "audio", "x-vnd.audioexplosion.mjuicemediafile" },
 | 
			
		||||
    { ".mjpg", "video", "x-motion-jpeg" },
 | 
			
		||||
    { ".mm", "application", "base64" },
 | 
			
		||||
    { ".mm", "application", "x-meme" },
 | 
			
		||||
    { ".mme", "application", "base64" },
 | 
			
		||||
    { ".mod", "audio", "mod" },
 | 
			
		||||
    { ".mod", "audio", "x-mod" },
 | 
			
		||||
    { ".moov", "video", "quicktime" },
 | 
			
		||||
    { ".mov", "video", "quicktime" },
 | 
			
		||||
    { ".movie", "video", "x-sgi-movie" },
 | 
			
		||||
    { ".mobileconfig", "application", "x-apple-aspen-config" },
 | 
			
		||||
    { ".mp2", "audio", "mpeg" },
 | 
			
		||||
    { ".mp2", "audio", "x-mpeg" },
 | 
			
		||||
    { ".mp2", "video", "mpeg" },
 | 
			
		||||
    { ".mp2", "video", "x-mpeg" },
 | 
			
		||||
    { ".mp2", "video", "x-mpeq2a" },
 | 
			
		||||
    { ".mp3", "audio", "mpeg3" },
 | 
			
		||||
    { ".mp3", "audio", "x-mpeg-3" },
 | 
			
		||||
    { ".mp3", "video", "mpeg" },
 | 
			
		||||
    { ".mp3", "video", "x-mpeg" },
 | 
			
		||||
    { ".mpa", "audio", "mpeg" },
 | 
			
		||||
    { ".mpa", "video", "mpeg" },
 | 
			
		||||
    { ".mpc", "application", "x-project" },
 | 
			
		||||
    { ".mpe", "video", "mpeg" },
 | 
			
		||||
    { ".mpeg", "video", "mpeg" },
 | 
			
		||||
    { ".mpg", "audio", "mpeg" },
 | 
			
		||||
    { ".mpg", "video", "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" },
 | 
			
		||||
    { ".p10", "application", "x-pkcs10" },
 | 
			
		||||
    { ".p12", "application", "pkcs-12" },
 | 
			
		||||
    { ".p12", "application", "x-pkcs12" },
 | 
			
		||||
    { ".p7a", "application", "x-pkcs7-signature" },
 | 
			
		||||
    { ".p7c", "application", "pkcs7-mime" },
 | 
			
		||||
    { ".p7c", "application", "x-pkcs7-mime" },
 | 
			
		||||
    { ".p7m", "application", "pkcs7-mime" },
 | 
			
		||||
    { ".p7m", "application", "x-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" },
 | 
			
		||||
    { ".pcl", "application", "x-pcl" },
 | 
			
		||||
    { ".pct", "image", "x-pict" },
 | 
			
		||||
    { ".pcx", "image", "x-pcx" },
 | 
			
		||||
    { ".pdb", "chemical", "x-pdb" },
 | 
			
		||||
    { ".pdf", "application", "pdf" },
 | 
			
		||||
    { ".pfunk", "audio", "make" },
 | 
			
		||||
    { ".pfunk", "audio", "make.my.funk" },
 | 
			
		||||
    { ".pgm", "image", "x-portable-graymap" },
 | 
			
		||||
    { ".pgm", "image", "x-portable-greymap" },
 | 
			
		||||
    { ".pic", "image", "pict" },
 | 
			
		||||
    { ".pict", "image", "pict" },
 | 
			
		||||
    { ".pkg", "application", "x-newton-compatible-pkg" },
 | 
			
		||||
    { ".pko", "application", "vnd.ms-pki.pko" },
 | 
			
		||||
    { ".pl", "text", "plain" },
 | 
			
		||||
    { ".pl", "text", "x-script.perl" },
 | 
			
		||||
    { ".plx", "application", "x-pixclscript" },
 | 
			
		||||
    { ".pm", "image", "x-xpixmap" },
 | 
			
		||||
    { ".pm", "text", "x-script.perl-module" },
 | 
			
		||||
    { ".pm4", "application", "x-pagemaker" },
 | 
			
		||||
    { ".pm5", "application", "x-pagemaker" },
 | 
			
		||||
    { ".png", "image", "png" },
 | 
			
		||||
    { ".pnm", "application", "x-portable-anymap" },
 | 
			
		||||
    { ".pnm", "image", "x-portable-anymap" },
 | 
			
		||||
    { ".pot", "application", "mspowerpoint" },
 | 
			
		||||
    { ".pot", "application", "vnd.ms-powerpoint" },
 | 
			
		||||
    { ".pov", "model", "x-pov" },
 | 
			
		||||
    { ".ppa", "application", "vnd.ms-powerpoint" },
 | 
			
		||||
    { ".ppm", "image", "x-portable-pixmap" },
 | 
			
		||||
    { ".pps", "application", "mspowerpoint" },
 | 
			
		||||
    { ".pps", "application", "vnd.ms-powerpoint" },
 | 
			
		||||
    { ".ppt", "application", "mspowerpoint" },
 | 
			
		||||
    { ".ppt", "application", "powerpoint" },
 | 
			
		||||
    { ".ppt", "application", "vnd.ms-powerpoint" },
 | 
			
		||||
    { ".ppt", "application", "x-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" },
 | 
			
		||||
    { ".ra", "audio", "x-pn-realaudio-plugin" },
 | 
			
		||||
    { ".ra", "audio", "x-realaudio" },
 | 
			
		||||
    { ".ram", "audio", "x-pn-realaudio" },
 | 
			
		||||
    { ".ras", "application", "x-cmu-raster" },
 | 
			
		||||
    { ".ras", "image", "cmu-raster" },
 | 
			
		||||
    { ".ras", "image", "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" },
 | 
			
		||||
    { ".rm", "audio", "x-pn-realaudio" },
 | 
			
		||||
    { ".rmi", "audio", "mid" },
 | 
			
		||||
    { ".rmm", "audio", "x-pn-realaudio" },
 | 
			
		||||
    { ".rmp", "audio", "x-pn-realaudio" },
 | 
			
		||||
    { ".rmp", "audio", "x-pn-realaudio-plugin" },
 | 
			
		||||
    { ".rng", "application", "ringing-tones" },
 | 
			
		||||
    { ".rng", "application", "vnd.nokia.ringing-tone" },
 | 
			
		||||
    { ".rnx", "application", "vnd.rn-realplayer" },
 | 
			
		||||
    { ".roff", "application", "x-troff" },
 | 
			
		||||
    { ".rp", "image", "vnd.rn-realpix" },
 | 
			
		||||
    { ".rpm", "audio", "x-pn-realaudio-plugin" },
 | 
			
		||||
    { ".rt", "text", "richtext" },
 | 
			
		||||
    { ".rt", "text", "vnd.rn-realtext" },
 | 
			
		||||
    { ".rtf", "application", "rtf" },
 | 
			
		||||
    { ".rtf", "application", "x-rtf" },
 | 
			
		||||
    { ".rtf", "text", "richtext" },
 | 
			
		||||
    { ".rtx", "application", "rtf" },
 | 
			
		||||
    { ".rtx", "text", "richtext" },
 | 
			
		||||
    { ".rv", "video", "vnd.rn-realvideo" },
 | 
			
		||||
    { ".s", "text", "x-asm" },
 | 
			
		||||
    { ".s3m", "audio", "s3m" },
 | 
			
		||||
    { ".saveme", "application", "octet-stream" },
 | 
			
		||||
    { ".sbk", "application", "x-tbook" },
 | 
			
		||||
    { ".scm", "application", "x-lotusscreencam" },
 | 
			
		||||
    { ".scm", "text", "x-script.guile" },
 | 
			
		||||
    { ".scm", "text", "x-script.scheme" },
 | 
			
		||||
    { ".scm", "video", "x-scm" },
 | 
			
		||||
    { ".sdml", "text", "plain" },
 | 
			
		||||
    { ".sdp", "application", "sdp" },
 | 
			
		||||
    { ".sdp", "application", "x-sdp" },
 | 
			
		||||
    { ".sdr", "application", "sounder" },
 | 
			
		||||
    { ".sea", "application", "sea" },
 | 
			
		||||
    { ".sea", "application", "x-sea" },
 | 
			
		||||
    { ".set", "application", "set" },
 | 
			
		||||
    { ".sgm", "text", "sgml" },
 | 
			
		||||
    { ".sgm", "text", "x-sgml" },
 | 
			
		||||
    { ".sgml", "text", "sgml" },
 | 
			
		||||
    { ".sgml", "text", "x-sgml" },
 | 
			
		||||
    { ".sh", "application", "x-bsh" },
 | 
			
		||||
    { ".sh", "application", "x-sh" },
 | 
			
		||||
    { ".sh", "application", "x-shar" },
 | 
			
		||||
    { ".sh", "text", "x-script.sh" },
 | 
			
		||||
    { ".shar", "application", "x-bsh" },
 | 
			
		||||
    { ".shar", "application", "x-shar" },
 | 
			
		||||
    { ".shtml", "text", "html" },
 | 
			
		||||
    { ".shtml", "text", "x-server-parsed-html" },
 | 
			
		||||
    { ".sid", "audio", "x-psid" },
 | 
			
		||||
    { ".sit", "application", "x-sit" },
 | 
			
		||||
    { ".sit", "application", "x-stuffit" },
 | 
			
		||||
    { ".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" },
 | 
			
		||||
    { ".snd", "audio", "x-adpcm" },
 | 
			
		||||
    { ".sol", "application", "solids" },
 | 
			
		||||
    { ".spc", "application", "x-pkcs7-certificates" },
 | 
			
		||||
    { ".spc", "text", "x-speech" },
 | 
			
		||||
    { ".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" },
 | 
			
		||||
    { ".stl", "application", "vnd.ms-pki.stl" },
 | 
			
		||||
    { ".stl", "application", "x-navistyle" },
 | 
			
		||||
    { ".stp", "application", "step" },
 | 
			
		||||
    { ".sv4cpio", "application", "x-sv4cpio" },
 | 
			
		||||
    { ".sv4crc", "application", "x-sv4crc" },
 | 
			
		||||
    { ".svf", "image", "vnd.dwg" },
 | 
			
		||||
    { ".svf", "image", "x-dwg" },
 | 
			
		||||
    { ".svr", "application", "x-world" },
 | 
			
		||||
    { ".svr", "x-world", "x-svr" },
 | 
			
		||||
    { ".swf", "application", "x-shockwave-flash" },
 | 
			
		||||
    { ".t", "application", "x-troff" },
 | 
			
		||||
    { ".talk", "text", "x-speech" },
 | 
			
		||||
    { ".tar", "application", "x-tar" },
 | 
			
		||||
    { ".tbk", "application", "toolbook" },
 | 
			
		||||
    { ".tbk", "application", "x-tbook" },
 | 
			
		||||
    { ".tcl", "application", "x-tcl" },
 | 
			
		||||
    { ".tcl", "text", "x-script.tcl" },
 | 
			
		||||
    { ".tcsh", "text", "x-script.tcsh" },
 | 
			
		||||
    { ".tex", "application", "x-tex" },
 | 
			
		||||
    { ".texi", "application", "x-texinfo" },
 | 
			
		||||
    { ".texinfo", "application", "x-texinfo" },
 | 
			
		||||
    { ".text", "application", "plain" },
 | 
			
		||||
    { ".text", "text", "plain" },
 | 
			
		||||
    { ".tgz", "application", "gnutar" },
 | 
			
		||||
    { ".tgz", "application", "x-compressed" },
 | 
			
		||||
    { ".tif", "image", "tiff" },
 | 
			
		||||
    { ".tif", "image", "x-tiff" },
 | 
			
		||||
    { ".tiff", "image", "tiff" },
 | 
			
		||||
    { ".tiff", "image", "x-tiff" },
 | 
			
		||||
    { ".tr", "application", "x-troff" },
 | 
			
		||||
    { ".tsi", "audio", "tsp-audio" },
 | 
			
		||||
    { ".tsp", "application", "dsptype" },
 | 
			
		||||
    { ".tsp", "audio", "tsplayer" },
 | 
			
		||||
    { ".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" },
 | 
			
		||||
    { ".ustar", "multipart", "x-ustar" },
 | 
			
		||||
    { ".uu", "application", "octet-stream" },
 | 
			
		||||
    { ".uu", "text", "x-uuencode" },
 | 
			
		||||
    { ".uue", "text", "x-uuencode" },
 | 
			
		||||
    { ".vcd", "application", "x-cdlink" },
 | 
			
		||||
    { ".vcs", "text", "x-vcalendar" },
 | 
			
		||||
    { ".vda", "application", "vda" },
 | 
			
		||||
    { ".vdo", "video", "vdo" },
 | 
			
		||||
    { ".vew", "application", "groupwise" },
 | 
			
		||||
    { ".viv", "video", "vivo" },
 | 
			
		||||
    { ".viv", "video", "vnd.vivo" },
 | 
			
		||||
    { ".vivo", "video", "vivo" },
 | 
			
		||||
    { ".vivo", "video", "vnd.vivo" },
 | 
			
		||||
    { ".vmd", "application", "vocaltec-media-desc" },
 | 
			
		||||
    { ".vmf", "application", "vocaltec-media-file" },
 | 
			
		||||
    { ".voc", "audio", "voc" },
 | 
			
		||||
    { ".voc", "audio", "x-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" },
 | 
			
		||||
    { ".vrml", "model", "vrml" },
 | 
			
		||||
    { ".vrml", "x-world", "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" },
 | 
			
		||||
    { ".wav", "audio", "x-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" },
 | 
			
		||||
    { ".wp5", "application", "wordperfect6.0" },
 | 
			
		||||
    { ".wp6", "application", "wordperfect" },
 | 
			
		||||
    { ".wpd", "application", "wordperfect" },
 | 
			
		||||
    { ".wpd", "application", "x-wpwin" },
 | 
			
		||||
    { ".wq1", "application", "x-lotus" },
 | 
			
		||||
    { ".wri", "application", "mswrite" },
 | 
			
		||||
    { ".wri", "application", "x-wri" },
 | 
			
		||||
    { ".wrl", "application", "x-world" },
 | 
			
		||||
    { ".wrl", "model", "vrml" },
 | 
			
		||||
    { ".wrl", "x-world", "x-vrml" },
 | 
			
		||||
    { ".wrz", "model", "vrml" },
 | 
			
		||||
    { ".wrz", "x-world", "x-vrml" },
 | 
			
		||||
    { ".wsc", "text", "scriplet" },
 | 
			
		||||
    { ".wsrc", "application", "x-wais-source" },
 | 
			
		||||
    { ".wtk", "application", "x-wintalk" },
 | 
			
		||||
    { ".xbm", "image", "x-xbitmap" },
 | 
			
		||||
    { ".xbm", "image", "x-xbm" },
 | 
			
		||||
    { ".xbm", "image", "xbm" },
 | 
			
		||||
    { ".xdr", "video", "x-amt-demorun" },
 | 
			
		||||
    { ".xgz", "xgl", "drawing" },
 | 
			
		||||
    { ".xif", "image", "vnd.xiff" },
 | 
			
		||||
    { ".xl", "application", "excel" },
 | 
			
		||||
    { ".xla", "application", "excel" },
 | 
			
		||||
    { ".xla", "application", "x-excel" },
 | 
			
		||||
    { ".xla", "application", "x-msexcel" },
 | 
			
		||||
    { ".xlb", "application", "excel" },
 | 
			
		||||
    { ".xlb", "application", "vnd.ms-excel" },
 | 
			
		||||
    { ".xlb", "application", "x-excel" },
 | 
			
		||||
    { ".xlc", "application", "excel" },
 | 
			
		||||
    { ".xlc", "application", "vnd.ms-excel" },
 | 
			
		||||
    { ".xlc", "application", "x-excel" },
 | 
			
		||||
    { ".xld", "application", "excel" },
 | 
			
		||||
    { ".xld", "application", "x-excel" },
 | 
			
		||||
    { ".xlk", "application", "excel" },
 | 
			
		||||
    { ".xlk", "application", "x-excel" },
 | 
			
		||||
    { ".xll", "application", "excel" },
 | 
			
		||||
    { ".xll", "application", "vnd.ms-excel" },
 | 
			
		||||
    { ".xll", "application", "x-excel" },
 | 
			
		||||
    { ".xlm", "application", "excel" },
 | 
			
		||||
    { ".xlm", "application", "vnd.ms-excel" },
 | 
			
		||||
    { ".xlm", "application", "x-excel" },
 | 
			
		||||
    { ".xls", "application", "excel" },
 | 
			
		||||
    { ".xls", "application", "vnd.ms-excel" },
 | 
			
		||||
    { ".xls", "application", "x-excel" },
 | 
			
		||||
    { ".xls", "application", "x-msexcel" },
 | 
			
		||||
    { ".xlt", "application", "excel" },
 | 
			
		||||
    { ".xlt", "application", "x-excel" },
 | 
			
		||||
    { ".xlv", "application", "excel" },
 | 
			
		||||
    { ".xlv", "application", "x-excel" },
 | 
			
		||||
    { ".xlw", "application", "excel" },
 | 
			
		||||
    { ".xlw", "application", "vnd.ms-excel" },
 | 
			
		||||
    { ".xlw", "application", "x-excel" },
 | 
			
		||||
    { ".xlw", "application", "x-msexcel" },
 | 
			
		||||
    { ".xm", "audio", "xm" },
 | 
			
		||||
    { ".xml", "application", "xml" },
 | 
			
		||||
    { ".xml", "text", "xml" },
 | 
			
		||||
    { ".xmz", "xgl", "movie" },
 | 
			
		||||
    { ".xpix", "application", "x-vnd.ls-xpix" },
 | 
			
		||||
    { ".xpm", "image", "x-xpixmap" },
 | 
			
		||||
    { ".xpm", "image", "xpm" },
 | 
			
		||||
    { ".x-png", "image", "png" },
 | 
			
		||||
    { ".xsr", "video", "x-amt-showrun" },
 | 
			
		||||
    { ".xwd", "image", "x-xwd" },
 | 
			
		||||
    { ".xwd", "image", "x-xwindowdump" },
 | 
			
		||||
    { ".xyz", "chemical", "x-pdb" },
 | 
			
		||||
    { ".z", "application", "x-compress" },
 | 
			
		||||
    { ".z", "application", "x-compressed" },
 | 
			
		||||
    { ".zip", "application", "x-compressed" },
 | 
			
		||||
    { ".zip", "application", "x-zip-compressed" },
 | 
			
		||||
    { ".zip", "application", "zip" },
 | 
			
		||||
    { ".zip", "multipart", "x-zip" },
 | 
			
		||||
    { ".zoo", "application", "octet-stream" },
 | 
			
		||||
    { ".zsh", "text", "x-script.zsh" }
 | 
			
		||||
  ]
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def inline(path, filename \\ nil) do
 | 
			
		||||
    case path |> Path.expand |> File.read do
 | 
			
		||||
      { :ok, data } ->
 | 
			
		||||
        {
 | 
			
		||||
          :ok,
 | 
			
		||||
          %Mailex.Attachment{
 | 
			
		||||
            filename:  filename || Path.basename(path),
 | 
			
		||||
            type:      guess_mime_type(path),
 | 
			
		||||
            data:      data
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      { :error, message } -> { :error, message }
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def inline!(path, filename \\ nil) do
 | 
			
		||||
    case inline(path, filename) do
 | 
			
		||||
      { :ok, attachment } -> attachment
 | 
			
		||||
      { :error, message } -> throw message
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def mime_types, do: @mime_types
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def guess_mime_type(path) do
 | 
			
		||||
    extension = Path.extname(path)
 | 
			
		||||
    type = Enum.find mime_types, fn({ext, _, _}) -> ext == extension end
 | 
			
		||||
    if (type) do
 | 
			
		||||
      { elem(type, 1), elem(type, 2)  }
 | 
			
		||||
    else
 | 
			
		||||
      { "application", "octet-stream" }
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										5
									
								
								lib/mailex/email.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								lib/mailex/email.ex
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,5 @@
 | 
			
		||||
defmodule Mailex.Email do
 | 
			
		||||
 | 
			
		||||
  defstruct subject: nil, from: nil, reply_to: nil, to: nil, cc: nil, bcc: nil, attachments: nil, html: nil, text: nil
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
							
								
								
									
										137
									
								
								lib/mailex/render.ex
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								lib/mailex/render.ex
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,137 @@
 | 
			
		||||
defmodule Mailex.Render do
 | 
			
		||||
 | 
			
		||||
  alias Mailex.Address
 | 
			
		||||
 | 
			
		||||
  def render(email) do
 | 
			
		||||
    mimemail_args = []
 | 
			
		||||
    if email.text, do:
 | 
			
		||||
      mimemail_args = [ { :plain, email.text } | mimemail_args]
 | 
			
		||||
    if email.html, do:
 | 
			
		||||
      mimemail_args = [ { :html, email.html } | mimemail_args]
 | 
			
		||||
    if email.attachments, do:
 | 
			
		||||
      mimemail_args = [ Enum.map(email.attachments, fn(a) -> { :attachment, a.data, a } end) | mimemail_args ]
 | 
			
		||||
 | 
			
		||||
    mimemail_args |> List.flatten |> to_tuple(email) |> :mimemail.encode
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def to_tuple(part, _email) when is_tuple(part) do
 | 
			
		||||
    {
 | 
			
		||||
      mime_type_for(part),
 | 
			
		||||
      mime_subtype_for(part),
 | 
			
		||||
      [],
 | 
			
		||||
      parameters_for(part),
 | 
			
		||||
      elem(part, 1)
 | 
			
		||||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def to_tuple(parts, email) when is_list(parts) do
 | 
			
		||||
    {
 | 
			
		||||
      mime_type_for(parts),
 | 
			
		||||
      mime_subtype_for(parts),
 | 
			
		||||
      headers_for(email),
 | 
			
		||||
      [],
 | 
			
		||||
      Enum.map(parts, &to_tuple(&1, email))
 | 
			
		||||
    }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def parameters_for({:attachment, _body, attachment}) do
 | 
			
		||||
    [
 | 
			
		||||
      { "transfer-encoding", "base64" },
 | 
			
		||||
      content_type_params_for(attachment),
 | 
			
		||||
      disposition_for(attachment),
 | 
			
		||||
      disposition_params_for(attachment)
 | 
			
		||||
    ]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def parameters_for(_part) do
 | 
			
		||||
    [
 | 
			
		||||
      { "transfer-encoding", "quoted-printable" },
 | 
			
		||||
      { "content-type-params", [] },
 | 
			
		||||
      { "disposition", "inline" },
 | 
			
		||||
      { "disposition-params", [] }
 | 
			
		||||
    ]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def content_type_params_for(attachment) do
 | 
			
		||||
    { "content-type-params", [{ "name", attachment.filename }] }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def disposition_for(_attachment) do
 | 
			
		||||
    { "disposition", "attachment" }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def disposition_params_for(attachment) do
 | 
			
		||||
    { "disposition-params", [{ "filename", attachment.filename }] }
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def mime_type_for(parts) when is_list(parts) do
 | 
			
		||||
    "multipart"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def mime_type_for({_type, _}) do
 | 
			
		||||
    "text"
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def mime_type_for({_, _, attachment}) do
 | 
			
		||||
    elem(attachment.type, 0)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def mime_subtype_for(parts) when is_list(parts) do
 | 
			
		||||
    if Enum.find parts, fn(part) -> elem(part, 0) == :attachment end do
 | 
			
		||||
      "mixed"
 | 
			
		||||
    else
 | 
			
		||||
      "alternative"
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def mime_subtype_for({type, _}) do
 | 
			
		||||
    type
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def mime_subtype_for({_, _, attachment}) do
 | 
			
		||||
    elem(attachment.type, 1)
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def headers_for(email) do
 | 
			
		||||
    headers = []
 | 
			
		||||
 | 
			
		||||
    if  email.reply_to, do:
 | 
			
		||||
      headers = [ { "Reply-To", email.reply_to |> stringify_addresses } ]
 | 
			
		||||
 | 
			
		||||
    if email.bcc, do:
 | 
			
		||||
      headers = [ { "Bcc", email.bcc |> stringify_addresses } | headers ]
 | 
			
		||||
 | 
			
		||||
    if email.cc, do:
 | 
			
		||||
      headers = [ { "Cc", email.cc |> stringify_addresses } | headers ]
 | 
			
		||||
 | 
			
		||||
    [ { "From",    email.from |> stringify_addresses },
 | 
			
		||||
      { "To",      email.to   |> stringify_addresses },
 | 
			
		||||
      { "Subject", email.subject || "" }  | headers ]
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  def stringify_addresses(addresses) do
 | 
			
		||||
    addresses = addresses |> Address.rfc_822_format
 | 
			
		||||
    if is_list(addresses) do
 | 
			
		||||
      Enum.join(addresses, ", ")
 | 
			
		||||
    else
 | 
			
		||||
      addresses
 | 
			
		||||
    end
 | 
			
		||||
  end
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
end
 | 
			
		||||
		Reference in New Issue
	
	Block a user