Improved support for format=flowed
I have recently been attempting to use mu4e to send and read emails with Content-Type: text/plain; format=flowed as described in the FAQ. Unfortunately, I have run into some issues.
Issues reading format=flowed emails
By default, mu4e does not reflow emails. The RFC states that
A series of one or more flowed lines followed by one fixed line is considered a paragraph, and MAY be flowed (wrapped and unwrapped) as appropriate on display.
Despite the permissive language, this feature seems worth implementing if mu4e is interested in supporting format=flowed – my understanding is that the whole point of format=flowed is to support receiver reformatting, so leaving it out seems like a large omission. Additionally, at least some mu4e users intentionally send format=flowed emails with especially long lines on the expectation that receiving clients will flow them; not reflowing these emails is likely to create an especially bad reading experience.
Additionally, both Mutt and Gnus reflowformat=flowed emails by default (Mutt with the reflow_text and reflow_wrap properties and Gnus with fill-flowed-display-column).
Potential fixes
Two simple workarounds exist. First, the mu4e-view-fill-long-lines function lets users achieve something similar to reflowing text (although it ties the size of the text to fill-column – which is set for writing and thus may be smaller than ideal for reading to allow room for quoting.)
Second, users can switch to the experimental gnus viewer mode (with (setq mu4e-view-use-gnus t)). As I mentioned, gnus already reflows format=flowed messages, which resolves the issue.
A longer-term fix would probably involve reflowing text based on the fill-flowed-display-column in the main mu4e viewer. This seems especially appropriate given that mu4e already uses the similar fill-flowed-encode-column when sending format=flowed emails.
Problems sending format=flowed emails
The problem with sending format=flowed emails arises is explained in the FAQ:
The transformation of your message into the proper format is done at the time of sending. For this to happen properly, you should write each paragraph of your message of as a long line (i.e. without carriage return).
This technically works, but creates a very awkward writing experience for anyone using an Emacs window that is significantly wider than a comfortable line length. (And allowing for users with differing screen widths is the core reason for format=flowed.) Because of this restriction, mu4e users cannot use auto-fill-mode, fill-paragraph, or any other function they might otherwise use to manage line length.
Potential fix
I suggest solving this issue by reflowing user text immediately before it is sent. Specifically, text should be filled to a length equal to fill-flowed-encode-column and should then have a space inserted just before their newline. This would create the "soft linebreak" called for in the format=flowed RFC regardless of any changes the user might have made to the line length when composing the message. (The function should skip lines that the user manually formatted with a hard line break, however.) I have implemented a personal version of this fix, which I have pasted below and would be happy to see mu4e adopt something similar.
(use-package mu4e
:commands mu4e
:init
(defun mu4e-fill-buffer-for-flowed ()
"Fill all lines in buffer to match format=flowed email spec.
Specifically, fills all *paragraph* lines to the number of columns
specified in fill-code-encode-column and ends each paragraph line
with a space followed by a newline, following the specification.
Non-paragraph lines are not filled, allowing for manual formatting.
A line is a non-paragraph line if it, plus the following word on the
next line, are short enough that they would not have been filled by
(fill-paragraph) based on the current value of fill-column. The effect
of this feature is that you can compose messages with auto-fill-mode on
(to have a comfortable line length for writing) and any lines that were
long enough to have been altered by auto-fill-mode will be refilled
(potentially to a different length) and padded with a final space to
match the fill=flowed RFC."
(interactive)
(end-of-buffer)
(message "start fn")
(mu4e-compose-goto-top)
(narrow-to-region (point-max) (point))
(message "start loop")
(while (not (eobp))
(message "%s" (thing-at-point 'line t))
(when (> (save-excursion (forward-line 1)
(forward-word)
(point))
(+ (point-at-bol) fill-column))
(beginning-of-line)
(let ((fill-column fill-flowed-encode-column))
(fill-paragraph))
(end-of-line)
(insert " "))
(end-of-line 2))
(message "end of loop")
(widen))
(defun mu4e-fill-send-and-exit ()
"Reflow the message text with (mu4e-fill-buffer-for-flowed) and send it."
(interactive)
(mu4e-fill-buffer-for-flowed)
(message-send-and-exit))
For the mu4e viewer.… we're slowly moving to the gnus-based one, so I don't really want to make any big changes there.
For the composer, that could be useful; perhaps you could make a PR? Instead of mu4e-fill-send-and-exit, guess we could use messsage-send-hook?
Ah, with the new message composer, flowing seems to work good-enough for me, so I'm going to close this. If you want something more than that, perhaps a function like the above can help. Thanks!