types of email: plain rfc2822 single-part MIME document multipart MIME document encapsulated message signed Desires: Be able to process and add parts messages without fully decoding the whole message. However, we do require some level of look ahead. For example, you may have to may have to look through all the header fields to find if the MIME-Version field is present or not. Be able to manipulate MIME messages with out losing comments, etc. Be able to generate messages. \section{Extensible vs. Homogeneous} There is a trade-off to consider. We can make the data-type be extensible so that we can later extend the library to handle additional RFCs. However, this will likely result in different messages having different types -- or we have to use some sort of dynamic typing system. The other option is to pick a uniform data type that can represent all the types of messages we want to handle, ranging from simple non-MIME RFC822 messages, to fancy multipart MIME messages. This allows us to create a homogenous list of messages, e.g. [Message]. It also results in simplier type signatures and a simpler API. Since the MIME system is not being extended much these days, it seems better to pick a simple, uniform data that encapsulates everthing. A MIME message must have a MIME-Version header field. Currently (and probably forever) the only version is 1.0. However, the field can contain comments, which we would like to preserve. We would also like to preserve the order of the headers, since this can be useful information -- for example the headers inserted by the different mail relays. For MIME messages, there are certain headers that are required or commonly accessed -- so it would be nice to have those fields built-in to the data type. However, that makes it difficult to maintain the order of the header fields. Rather than store that 'cached' data in the type, perhaps it should be the responsiblity of the user to cache the fields they care about. This keeps the interface simple and uniform -- and does not add caching requirements to programs that do not even use those fields. We also want to be able to continue in the face of errors when appropriate -- but also report errors. The ContentType and ContentEncoding are found it the headers, and describe the body. In our type, should we keep them in the header part, or the body part ? It is valid for them to appear in all media types. \begin{code} import Data.ByteString.Char8 type Name = ByteString type Value = ByteString type Line = Int type Col = Int type Pos = (FilePath, Line, Col) type Field = (Name, Value) type Headers = [Field] data Part = Part Headers Body \end{code} \begin{code} type Boundary = String type Preamble = ByteString type Epilogue = ByteString data Body = Discrete Bool ByteString -- ^ encoded/decoded, data | Multipart Preamble [Part] Epilogue -- boundary is part of the the content-type | Message Part data MultipartSubtype = Mixed | Alternative | Digest | Parallel | Other String deriving Show {- data MessageSubtype = RFC2822 | Partial deriving Show instance Show MultipartMessage where show (Part (ContentType ("text","plain") _) _ str) = str ++ "\n" show (Part (ContentType (mtype,subType) _) _ str) = mtype ++"/"++ subType++"\n" show (Mixed parts) = "multipart/mixed\n" ++ concatMap show parts -} \end{code} Perhaps we need a form that deals with already encoded data ? Though, we should often already have a complete part in that case. \begin{code} data ContentEncoding = ContentEncoding deriving Show data ContentType = ContentType deriving Show createDiscretePart :: ContentType -> ContentEncoding -> Headers -> ByteString -> Part createDiscretePart contentType contentEncoding additionalHeaders thedata = Part ((pack "Content-Type", pack $ show contentType) : (pack "Content-Encoding", pack $ show contentEncoding) : additionalHeaders) (Discrete True (encode contentEncoding thedata)) -- ContentType must include the boundary marker; How do we ensure that -- the boundary marker does not appear in the body? We can not check -- that until after it has been encoded. And, what do we do in the -- case that it does appear in the body? Note that if we allow the -- contents to be in memory an encoded or decoded state -- then we -- obviously must do some processing to create the mime document -- anyway. createMultiPart :: ContentType -> Preamble -> [Part] -> Epilogue -> Part createMultiPart createMultiPart = undefined encode = undefined \end{code}