[RFC] writing HTML email with notmuch
Antoine Beaupré
anarcat at orangeseeds.org
Mon Feb 25 15:01:55 PST 2019
I seem to have forgotten to CC the list in my reply, sorry for the
noise.
I elided the attachment here because I sent a newer version in
87r2bvjx02.fsf at curie.anarc.at.
A.
On 2019-02-25 17:11:26, Antoine Beaupré wrote:
> On 2019-02-25 16:18:03, Daniel Kahn Gillmor wrote:
>> Hi Antoine--
>>
>> thanks for an entertaining and thoughtful read.
>>
>> Your elisp rendered really strangely for me in notmuch mode in emacs:
>>
>> (widen)
>> (save-excursion
>> (set-buffer output-buffer-name)
>> (markdown-add-xhtml-header-and-footer ""))
>> (insert "
>> [ multipart/alternative ]
>> [ text/plain ]
>> \n")
>> (end-of-buffer)
>> (insert "
>> [ text/html (hidden) ]
>> \n") (insert-buffer output-buffer-name) (insert "
>> [ text/plain ]
>> ;; remove Markdown <pre> markings
>> (goto-char signature-position)
>>
>> (note the []-delimited emacs buttons above)
>>
>> The issue here appears to be that the MIME boundaries in your message (i
>> won't repeat them here because i don't want to break my own message) are
>> getting mixed up/confused somehow with the mime boundaries you include
>> in the elisp.
>>
>> I'd be happy to compare raw files with you at some point if you want to
>> try to make sense of this. I'm hoping that the error is in the message
>> generation (that your sending MUA garbled your elisp) rather than in the
>> receipt, because if the receiving side is at fault it's a much worse
>> security risk.
>
> Haha... That's actually kind of hilarious.
>
> I can confirm the badness occured on send here. I've attached my
> precious notmuch-config.el, which has that function (and many more!) as
> a real attachement which should workaround those issues.
>
> ;; autocompletion
> (eval-after-load "notmuch-address"
> '(progn
> (notmuch-address-message-insinuate)))
>
> ; don't remember what that is
> (add-hook 'notmuch-show-hook 'visual-line-mode)
>
> (defun notmuch-load-bug (bug)
> "download and show a Debian bug report with notmuch-slurp-debbug"
> (interactive "MDebian bug number: ")
> (message "downloading debian bug %s..." bug)
> (call-process "notmuch-slurp-debbug" nil nil nil bug)
> (message "running notmuch-poll...")
> (notmuch-poll)
> (message "searching for bug %s..." bug)
> (notmuch-search bug)
> (message "bug %s loaded, but really you should use upstream notmuch-slurp-debbug" bug))
>
> ;; attachment checks
> ;;
> ;; should be sent upstream, but needs unit tests in test/T310-emacs.sh
> (defcustom notmuch-message-attach-regex
> "\\b\\(attache\?ment\\|attached\\|attach\\|pi[¨e]ce\s+jointe?\\)\\b"
> "Pattern of text announcing there should be an attachment.
>
> This is used by `notmuch-message-check-attach' to check email
> bodies for words that might indicate the email should have an
> attachement. If the pattern matches and there is no attachment (a
> `<#part ...>' magic block), notmuch will show a confirmation
> prompt before sending the email.
>
> The default regular expression is deliberately liberal: we prefer
> false positive than forgotten attachments. This should be
> customized for non-english languages and notmuch welcomes
> additions to the pattern for your native language, unless it
> conflicts with common words in other languages."
> :type '(regexp)
> :group 'notmuch-send)
>
> (defun notmuch-message-check-attach ()
> """Check for missing attachments.
>
> This is normally added to `message-send-hook' and is configured
> through `notmuch-message-attach-regex'."""
> (save-excursion ;; XXX: this fails somehow: point is at the end of the buffer on error
> (goto-char (point-min))
> (if (re-search-forward notmuch-message-attach-regex nil t)
> (progn
> (goto-char (point-min))
> (unless (re-search-forward "<#part [^>]*filename=[^>]*>" nil t)
> (or (y-or-n-p "Email seem to refer to attachment, but nothing attached, send anyways?")
> (error "No attachment found, aborting")))))))
>
> (defcustom notmuch-mua-attachment-regexp
> "\\b\\(attache\?ment\\|attached\\|attach\\|pi[¨e]ce\s+jointe?\\)\\b"
> "Message body text indicating that an attachment is expected.
>
> This is not used unless `notmuch-mua-attachment-check' is added
> to `notmuch-mua-send-hook'.")
>
> (defun notmuch-mua-attachment-check ()
> "Signal an error if the message text indicates that an
> attachment is expected but no MML referencing an attachment is
> found.
>
> Typically this is added to `notmuch-mua-send-hook'."
> (when (and
> ;; When the message mentions attachment...
> (save-excursion
> (message-goto-body)
> (loop while (re-search-forward notmuch-mua-attachment-regexp (point-max) t)
> ;; For every instance of the "attachment" string
> ;; found, examine the text properties. If the text
> ;; has either a `face' or `syntax-table' property
> ;; then it is quoted text and should *not* cause the
> ;; user to be asked about a missing attachment.
> if (let ((props (text-properties-at (match-beginning 0))))
> (not (or (memq 'syntax-table props)
> (memq 'face props))))
> return t
> finally return nil))
> ;; ...but doesn't have a part with a filename...
> (save-excursion
> (message-goto-body)
> (not (re-search-forward "^<#part [^>]*filename=" nil t)))
> ;; ...and that's not okay...
> (not (y-or-n-p "Attachment mentioned, but no attachment - is that okay?")))
> ;; ...signal an error.
> (error "Missing attachment")))
>
> (add-hook 'message-send-hook 'notmuch-mua-attachment-check)
> (add-hook 'message-send-hook 'notmuch-draft--mark-deleted)
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;;; keymappings
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (define-key notmuch-show-mode-map "S"
> (lambda ()
> "mark message as spam and advance"
> (interactive)
> (notmuch-show-tag '("+spam" "-inbox" "-ham" "-unread" "-flagged"))
> (notmuch-show-next-open-message t)))
>
> (define-key notmuch-search-mode-map "S"
> (lambda (&optional beg end)
> "mark message as spam and advance"
> (interactive (notmuch-search-interactive-region))
> (notmuch-search-tag (list "+spam" "-inbox" "-ham" "-unread" "-flagged") beg end t)
> (anarcat/notmuch-search-next-thread)))
>
> (define-key notmuch-show-mode-map "H"
> (lambda ()
> "mark message as ham and advance"
> (interactive)
> (notmuch-show-tag '("-spam" "-greyspam" "+inbox" "+ham" "+flagged"))
> (notmuch-show-next-open-message t)))
>
> (define-key notmuch-search-mode-map "H"
> (lambda (&optional beg end)
> "mark message as ham and advance"
> (interactive (notmuch-search-interactive-region))
> (notmuch-search-tag (list "-spam" "-greyspam" "+inbox" "+ham" "+flagged") beg end t)
> (anarcat/notmuch-search-next-thread)))
>
> (define-key notmuch-search-mode-map "u"
> (lambda (&optional beg end)
> "undelete and advance"
> (interactive (notmuch-search-interactive-region))
> (notmuch-search-tag (list "-deleted") beg end t)
> (anarcat/notmuch-search-next-thread)))
>
> (define-key notmuch-search-mode-map "d"
> (lambda (&optional beg end)
> "delete and advance"
> (interactive (notmuch-search-interactive-region))
> (notmuch-search-tag (list "+deleted" "-unread") beg end t)
> (anarcat/notmuch-search-next-thread)))
>
> (define-key notmuch-show-mode-map "d"
> (lambda ()
> "delete current message and advance"
> (interactive)
> (notmuch-show-tag '("+deleted" "-unread"))
> (notmuch-show-next-open-message t)))
>
> ;; https://notmuchmail.org/emacstips/#index17h2
> (define-key notmuch-show-mode-map "b"
> (lambda (&optional address)
> "Bounce the current message."
> (interactive "sBounce To: ")
> (notmuch-show-view-raw-message)
> (message-resend address)
> (kill-buffer)))
>
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ;;; my custom notmuch functions
> ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> (defun anarcat/notmuch-search-next-thread ()
> "Skip to next message from region or point
>
> This is necessary because notmuch-search-next-thread just starts
> from point, whereas it seems to me more logical to start from the
> end of the region."
> ;; move line before the end of region if there is one
> (unless (= beg end)
> (goto-char (- end 1)))
> (notmuch-search-next-thread))
>
> ;; Linking to notmuch messages from org-mode
> ;; https://notmuchmail.org/emacstips/#index23h2
> (require 'org-notmuch nil t)
> (autoload 'gnus-alias-determine-identity "gnus-alias" "" t)
> (add-hook 'message-setup-hook 'gnus-alias-determine-identity)
>
> (defun anarcat/notmuch-html-convert ()
> """create an HTML part from a Markdown body
>
> This will not work if there are *any* attachments of any form, those should be added after."""
> (interactive)
> (save-excursion
> ;; wrap signature in a <pre>
> (message-goto-signature)
> (forward-line -1)
> ;; save and delete signature which requires special formatting
> (setq signature (buffer-substring (point) (point-max)))
> (delete-region (point) (point-max))
> ;; set region to top of body then end of buffer
> (end-of-buffer)
> (message-goto-body)
> (narrow-to-region (point) (mark))
> ;; run markdown on region
> (setq output-buffer-name "*notmuch-markdown-output*")
> (markdown output-buffer-name)
> (widen)
> (save-excursion
> (set-buffer output-buffer-name)
> (end-of-buffer)
> ;; add signature formatted as <pre>
> (insert "\n<pre>")
> (insert signature)
> (insert "</pre>\n")
> (markdown-add-xhtml-header-and-footer ""))
> ;; restore signature
> (message-goto-signature)
> (insert signature)
> (message-goto-body)
> (insert "<#multipart type=alternative>\n")
> (end-of-buffer)
> (insert "<#part type=text/html>\n")
> (insert-buffer output-buffer-name)
> (end-of-buffer)
> (insert "<#/multipart>\n")
> ;; remove Markdown <pre> markings
> (goto-char signature-position)
> (while (re-search-forward "^```" nil t)
> (replace-match ""))))
>
> (message "anarcat's custom notmuch config loaded")
>
>> On Sun 2019-02-24 20:52:40 -0500, Antoine Beaupré wrote:
>>> PPS: I remember reading about someone wanting to declare a text/markdown
>>> mimetype for email, and remembering it was all backwards and weird and I
>>> can't find the reference anymore. If some lazyweb magic person could
>>> forward the link to me I would be grateful.
>>
>> https://tools.ietf.org/html/rfc7763 -- I'm sure Sean Leonard (the author
>> of this informational RFC) would be open to discussion about what's
>> missing or what could be improved.
>
> I remember reading that RFC and not understanding the point of it, to be
> honest. I mean it's great to mark certain content as markdown - I
> sometimes did that when attaching drafts to my editor, but really I
> would be worried about marking (say) this email as text/markdown because
> I'd be afraid most MUAs wouldn't display it correctly.
>
> But this wasn't the article I had in mind - it was something about doing
> the opposite conversion, if my memory is correct.
>
> A.
> --
> I've got to design so you can put it together out of garbage cans. In
> part because that's what I started from, but mostly because I dont
> trust the industrial structurethey might decide to suppress us
> weirdos and try to deny us the parts we need.
> - Lee Felsenstein
--
My passionate sense of social justice and social responsibility has
always contrasted oddly with my pronounced lack of need for direct
contact with other human beings and communities. I am truly a "lone
traveler" and have never belonged to my country, my home, my friends,
or even my immediate family, with my whole heart; in the face of all
these ties, I have never lost a sense of distance and a need for
solitude.
- Albert Einstein
More information about the notmuch
mailing list