February 12, 2018
I use the mutt email client for sending and reading emails. I really like it since it has keyboard navigation and lets you compose emails in whichever text editor you like, of course I write them in Vim :)
The downside to writing emails in Vim is that you can choose to either wrap lines after a set amount (usually 80 characters) or not. If you don't, then your messages look bad as you write them like this:
Because of this, I keep the coding convention of inserting line breaks at 80 columns when writing emails to, which looks a lot nicer:
Of course Vim does the wrapping automatically, so I just type and it inserts new lines every 80 characters.
The problem with this is that it can look bad for the receiver of the email. If they have at least 80 characters in their display, then it looks OK, if a bit wasteful with space. Here is the email in Gmail:
Notice that the email doesn't fill the wide area because of the hard line breaks at 80 characters. Also most email viewers use variable-space fonts, so the lines won't even necessarily all look close to the same length.
Even worse, if you look at this email in a viewer with less than 80 characters, it will look awful. Here it is in the Gmail app on my phone:
Notice that the email wraps naturally at a certain point, and then the hard line break in the email causes the unnatural looking break.
In searching for a good solution to this, I came across format=flowed which looks like it would fix the issue. Unfortunately Exchange doesn't support it so I needed my own solution.
My solution is to have Vim wrap lines for me at 80 characters like normal, but to then fix the lines for me when I exit Vim. The first step of this is to hook up a program to run automatically when I finish writing an email. Putting this in the .vimrc file accomplishes that:
" command on all mutt files to remove augroup autocom autocmd! " executes my command on quit autocmd VimLeave /tmp/mutt-* !/home/finlayson/bin/email-process % augroup END
I don't really grok Vimscript, but to my understanding, this sets up an automatic command which is triggered when I leave Vim on files that match the /tmp/mutt-* pattern (which is where mutt stores email files when you compose them). Then it runs the /home/finlayson/bin/email-process script on them (the % expands to the name of the file).
Then all that is needed is the "email-process" program which fixes the formatting on the emails after they are written.
This can be done with a Python program. Here is what I came up with:
#!/usr/bin/python3 from sys import argv # open up the email contents file infile = open(argv, 'r') # read it into an array of strings w/o new lines body = [line.rstrip('\n') for line in infile] # close the input file infile.close() # returns if a line is OK to join with one above it # all but blank lines, # those that start with a > (because they are quotes) # ones starting with space (because they are blocks of code e.g.) def line_joinable(line): if len(line) == 0: return False if line == '>': return False if line in [' ', '\t']: return False return True # go through each line i = 0 while i < (len(body) - 1): line = body[i] next_line = body[i + 1] # if both lines are joinable, join them if line_joinable(line) and line_joinable(next_line): body[i] = body[i] + ' ' + body[i + 1] del body[i + 1] continue else: i += 1 # open the output file to overwrite it in place outfile = open(argv, 'w') for line in body: outfile.write("%s\n" % line) outfile.close()
Now when I write an email, the text wraps around at 80 characters, when I am done writing it, this program will reformat it to remove all of the line breaks, and it will display more nicely when viewed by the recipient.
Funny enough the reason there are some typos (like notwrapped being one word) in the images above was due to a bug in this program where it joined lines without putting a space in between. I fixed the bug, but didn't want to redo the images. Getting scripts involved with outgoing professional emails is really playing with fire...
Copyright © 2021 Ian Finlayson | Licensed under a Creative Commons Attribution 4.0 International License.