CL-MIME is a library for constructing and manipulating MIME objects in Common Lisp. It supports creating MIME content for emails or web pages and can also parse existing MIME content to create MIME objects for manipulation. Supports (semi-)automatic encoding and decoding of MIME parts in quoted-printable or base64 form.

This package requires use of cl-qprint, cl-base64 and cl-ppcre.


Author: Robert Marlow

License: LLGPL

Usage example

Small example to parse Thunderbird messages in mbox format:

(defun thunderbird-mbox-msg-to-text (email) (with-open-file (msg email :direction :input) (with-open-file (out (concatenate 'string (pathname-name x) ".txt") :direction :output :if-exists :supersede) (let ((mime (parse-mime msg))) (case (type-of mime) (text-mime (print (content mime) out)) (multipart-mime (dolist (part (content mime)) (if (and (string-equal (content-type part) "text") (string-equal (content-subtype part) "plain")) (print-mime out part nil nil)))) (mime (print "mime")) ;? (t (print "other"))))))) ;?

The MIME class is the mixin which TEXT-MIME and MULTIPART-MIME inherit from. Most plain text messages will be of type TEXT-MIME and you can read the body with the CONTENT function. MULTIPART-MIME messages have multiple parts, you will have to iterate over them inspecting the type and subtype of each and choose what to do with them. In the example above, I was extracting the plain text version of html emails. See the wikipedia page on MIME and help yourself.

Quick assessment (2023-04-05)

Tested with MKCL:

> (with-open-file (stream "M:/downloads/new.eml") (cl-mime:parse-mime stream)) #<a CL-MIME:MULTIPART-MIME 166614816> > (cl-mime:get-mime-headers *) ((:MIME-VERSION . "1.0") (:CONTENT-TYPE . "multipart/alternative; boundary=\"9f9ed95156ef51dd4088a1e5dc2b74a836bd9e70f09380894bde1b1a0fa9\"") (:CONTENT-TRANSFER-ENCODING . :7BIT)) > (cl-mime:header-parms (second *)) ((:BOUNDARY "9f9ed95156ef51dd4088a1e5dc2b74a836bd9e70f09380894bde1b1a0fa9")) > (cl-mime:print-headers *standard-output* ** t) MIME-Version: 1.0 Content-Type: multipart/alternative; boundary="9f9ed95156ef51dd4088a1e5dc2b74a836bd9e70f09380894bde1b1a0fa9" Content-Transfer-Encoding: 7bit NIL