pimalaya / himalaya

CLI to manage emails
https://pimalaya.org
MIT License
3.16k stars 95 forks source link

Implement the composer module #341

Closed soywod closed 1 year ago

soywod commented 2 years ago

Context

Frontends are not all equal in features when it comes to message composition. Emacs has some built-in features that makes the composition experience really great (contact completion, MML language for attachments, coloured syntax etc), whereas the Vim plugin is quite limited (only the coloured syntax), and TUI/GUI may be even worse.

Problem

For now, frontends use the save and send commands which requires raw MIME message. It means that frontends have the responsibility to produce valid MIME messages. The responsibility should be moved to the lib.

Solution

I propose to implement sth similar to what the MML language does in Emacs. This language allows us to write messages in a pseudo code (kind of a template). Then this template is "compiled" into a fully valid MIME message. For example, the following pseudo-message:

Subject: test

<#multipart type=mixed>
<#part type=image/jpeg filename=~/rms.jpg disposition=inline>
<#multipart type=alternative>
This is a plain text part.
<#part type=text/enriched name=enriched.txt>
<center>This is a centered enriched part</center>
<#/multipart>
This is a new plain text part.
<#part disposition=attachment>
This plain text part is an attachment.
<#/multipart>

will be compiled into:

Subject: test
Content-Type: multipart/mixed; boundary="=-=-="

--=-=-=

--=-=-=
Content-Type: image/jpeg;
 filename="~/rms.jpg"
Content-Disposition: inline;
 filename="~/rms.jpg"
Content-Transfer-Encoding: base64

/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAgGBgcGBQgHBwcJCQgKDBQNDAsLDBkSEw8UHRof
Hh0aHBwgJC4nICIsIxwcKDcpLDAxNDQ0Hyc5PTgyPC4zNDL/wAALCAAwADABAREA/8QAHwAA
AQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQR
BRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RF
RkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ip
qrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/9oACAEB
AAA/AO/rifFHjldNuGsrDa0qcSSHkA+gHrXKw+LtWLrMb+RgTyhbr+HSug07xNqV9fQtZrNI
AyiaE/NuBPOOOP0rvRNE880KOC8TbXXGCv1FPqjrF4LDR7u5L7SkTFT/ALWOP1xXgTuXfc7E
sx6nua6rwp4IvvEM8chCxWxOdzn7wz6V9AaB4S07w9p5itow0rDLSY5Pt9K43xO66P4xs71m
2QXiGCbA4yOVJ9+1aYORkdK434lyNH4ahCnG66VT9Nj15JFbPdX0MS43M4VQf5/yr2vSpLnw
5ZW8dlCZ8KFXjOPX0/mK6rSPEGt3Angu44fNEReHYNvIH3TzXDeKNO8RX+kSX2ouZkicTIOc
L+g7E810ulFjpVtv3bwgB3HJyK5L4quY/C9sVxk3ij/xx6850u7t1mtp/wDlpEw3An3Jr3Dw
34gsbWza4nBlhC5LDsaW6+IFgupQyCF3iHH7gA7c9R9ay7zx6t7aX9jHC4smhfBkGCvHGfrm
tLQ7hbnRrV1GPkAP1x1/Hr+Ncr8Vzjwrbf8AX6v/AKA9eQRyYlQk8Yx9K6XTNbkgia2ciSIn
7p5Ga9Atte0LTLKO6it4i7dVRFJDcZ4PvXN+JvEMF9bILVGXJLSZ4zkjivRPDaeX4b08HOTC
pOffmua+KkbS+GLVUGT9tT/0B68eeIpIFYjB70+OOVXyoOM9+M1eaWeCLzHPyHGO/NVWvJJm
jQ8KGH1NfQWhXSXmh2c8eArRLwO3HSv/2Q==

--=-=-=
Content-Type: multipart/alternative; boundary="==-=-="

--==-=-=

This is a plain text part.

--==-=-=
Content-Type: text/enriched;
 name="enriched.txt"

<center>This is a centered enriched part</center>

--==-=-=--

--=-=-=

This is a new plain text part.

--=-=-=
Content-Disposition: attachment

This plain text part is an attachment.

--=-=-=--
dvdsk commented 2 years ago

I think most TUI's would provide their own UI for setting the options expressed in the MML. How would they interface? Maybe builder pattern initialized struct that devs could hook in too?

Going through the above showed me I know little about mail. Because of that following is going to be wrong in many ways but it might be a good start to get thinking going:

use Content::{Jpeg, RichTxt};
let enriched = todo!("a string or possibly some rich text AST?");

let mail: MailMsg = MailComposer::new()
    .subject("test")
    .add(Jpeg{ 
        filename: "rms.jpg", 
        bytes: include_bytes!(rms.jpg) 
     })
    .add_plain("This is a plain text part.")
    .add(RichTxt{ 
        name: "enriched.txt", 
        ast: enriched
     }) 
    .add_plain("This is a new plain text part.")
    .attach("This plain text part is an attachment.")
    .compose(); // Note no unwrap types should allow only correct usage

This calls to mind a few questions:

soywod commented 2 years ago

The message builder already exists in the lettre 1 crate. Himalaya uses it to convert a message into a "sendable" one 2 (because the lettre crate also contains a SMTP client, so we can use it to build AND send messages). The question is how to interface a "message language" alla Emacs's MML with the lettre message builder?

The first step would be to develop a DSL (maybe using the nom crate 3). We just need some basic features from MML, like <!#part /> and <!#multipart />

The second step would be to map the parsed AST into a sendable message using the lettre message builder.

On 24 Mar 2022, at 22:14 (+0100), soywod/himalaya wrote:

I think most TUI's would provide their own UI for setting the options expressed in the MML. How would they interface? Maybe builder pattern initialized struct that devs could hook in too?

Going through the above showed me I know little about mail. Because of that following is going to be wrong in many ways but it might be a good start to get thinking going:

use Content::{Jpeg, RichTxt};
let enriched = todo!("a string or possibly some rich text AST?");

let mail: MailMsg = MailComposer::new()
 .subject("test")
 .add(Jpeg{ 
 filename: "rms.jpg", 
 bytes: include_bytes!(rms.jpg) 
 })
 .add_plain("This is a plain text part.")
 .add(RichTxt{ 
 name: "enriched.txt", 
 ast: enriched
 }) 
 .add_plain("This is a new plain text part.")
 .attach("This plain text part is an attachment.")
 .compose(); // Note no unwrap types should allow only correct usage

This calls to mind a few questions:

  • Should each variant of the Content enum have a Content-Disposition and Content-Transfer-Encoding field?
  • Does each content type need a name?

-- Reply to this email directly or view it on GitHub: https://github.com/soywod/himalaya/issues/341#issuecomment-1078337878 You are receiving this because you were assigned.

Message ID: @.***>

-- Cordialement Clément DOUIN Développeur Web Full-Stack https://soywod.me

soywod commented 1 year ago

Added by #431 :tada: