Advanced Namespace Tools blog

12 January 2018

Guide to configuring Plan 9 upas to work with gmail

It has been a few years since I was using Plan 9 for my email. I took a break from Plan 9 during 2014 and during that time fell back into the habit of using the web-gmail interface. I decided it was time to fix this, which meant figuring out, for the 3rd time or so, how to get 9front talking with gmail's servers. It only took a couple hours of feverish manpage and guide reading and debugging to get the config worked out. This particular configuration process is not the most graceful aspect of Plan 9, but the mail environment is very nice once it is set up. In general, configuring systems to work with non-plan 9 protocols is always going to be more of a hassle than staying entirely within the ecosystem, so I'm not saying I see a better way to do all this. I understand that the whole system was originally designed and intended for running your own mail server, not retrieving things from gmail, so the awkardness seems related to that.

Receiving and reading email - the easy part

Just being able to receive and read messages is easy. Step one - log into your gmail via the web interface, go to the account options, and tell it to allow less-secure login methods. Now, in your plan9 system, enter a command like this:

upas/fs -f /imaps/imap.gmail.com/myname@mydomain.com

This will spit out an error that looks like:

upas/fs: opening /imaps/imap.gmail.com/myname@mydomain.com: \
imap.gmail.com/imaps:cert for imap.gmail.com not recognized: \
sha256=x9n2C90RHrd4e97E/i21h9Ios0mKZJ9w3WDg9OE9Ud9

Now you can make that hash be recognized. Note the x509 prefix in the echo statement:

 echo 'x509 sha256=x9n2C90RHrd4e97E/i21h9Ios0mKZJ9w3WDg9OE9Ud9' >>/sys/lib/tls/mail

Now rerun the same upas/fs command as above, and factotum will prompt you for your password. Enter it, and upas will spend some time (which varies depending on the size of your mailbox) setting things up. Now you can start the mail program to read messages with the command

mail

The tricky part: configuration for sending mail

Given how nice and easy that was, one might hope sending mail would be equally simple. Not quite. The configuration for sending is considerably more involved. A first step:

echo 'key proto=pass server=smtp.gmail.com service=smtp user=myname@mydomain.com !password=yourpassword' >/mnt/factotum/ctl

With that done, we have two files to configure in /mail/lib. The first is /mail/lib/rewrite. There is a template to use located at /mail/lib/rewrite.gateway. The easiest thing to do is just append the template to the blank-except-for-comments original.

cat /mail/lib/rewrite.gateway >> /mail/lib/rewrite

Editing the rewrite file is pretty simple. The only section that usually needs to be changed is shown below, and the change is obvious.

# append the local domain to addresses without a domain
local!"(.+)"		alias		\1@mydomain.com
local!(.*)		alias		\1@mydomain.com

With that done, we are ready to configure /mail/lib/remotemail. The configuration shown below may not be perfectly well-constructed, but works in practice.

#!/bin/rc
shift
sender=myname@mydomain.com
shift
addr=smtp.gmail.com
shift
fd=`{/bin/upas/aliasmail -f $sender}
switch($fd){
case *.*
	;
case *
	fd=mydomain.com
}
echo exec /bin/upas/smtp -u myname@mydomain.com -a -h $fd $addr $sender $* >>/sys/log/remotemail
exec /bin/upas/smtp -u myname@mydomain.com -a -h $fd $addr $sender $*

Note the addition of the -a flag to the pre-existing upas/smtp command. The echo statement is purely optional extra logging. We are almost done! You can try sending some mail with

mail someone@somedomain

Note that the mail program makes use of rio's "hold" mode, so you need to enter your message, then press escape, then hit ctrl-d to EOF the data you are sending. Sending this first message will fail because we need to add another bit of tls related info.

cat /sys/log/smtp

Will show an error that looks like

Jan 11 20:40:43 cert for gmail-smtp-msa.l.google.com not recognized: sha256=gE9IwK9spTR9613V92I5+sVI9R0U9PLKyaZjr8OiNH9

Again, you need to add this in the right place, which in this case is /sys/lib/tls/smtp.

echo 'x509 sha256=gE9IwK9spTR9613V92I5+sVI9R0U9PLKyaZjr8OiNH9' >>/sys/lib/tls/smtp

If all of this is done correctly, you should now be able to send mail successfully using the mail command.

Namespaces for your faces

Assuming you got all this done correctly and you can send and receive mail, you probably want to use Plan9's famous "faces" program to help out. It shows new mails as they arrive, and if you right click on the face icon, it will open them for you in a new window. However, you have to have a plumber running underneath your current rio, and faces needs to be in a namespace with access to upas/fs. You want to see a namespace stack like this within the rio you are working within:

mount  '#s/plumb.user.15857' /mnt/plumb 
mount  '#|/data1' /mail/fs 
mount  '#s/rio.user.15869' /mnt/wsys 6

In other words, plumber first, then upas/fs, then start rio, then start faces within the rio. The conventional way to do this is having the plumber and upas started on your terminal from /usr/name/lib/profile.

Troubleshooting: check the logs

If something is misconfigured, you can often find out the problem from the logfiles. /sys/log/mail, /sys/log/runq, /sys/log/smtp, /sys/log/smtp.fail may all be relevant. I also added another log via the echo statement shown in remotemail, /sys/log/remotemail. Here is a summary of what needs to be done - check above for full details.

Reading mail

Sending mail

Using multiple accounts

(The following information was provided by qwx)

I need to monitor multiple mailboxes, and be able to select from which one I should send. In order to select a different account from which to send from, you need to:

My hacky solution so far is to just add a switch-case statement to remotemail, like:

; cat /mail/lib/remotemail
#!/bin/rc
shift
sender=$1
shift
addr=$1
shift
if(~ gmail.com `{echo $sender | sed 's/^[^@]+@//'}){
	fd=gmail.com
	addr=tcp!smtp.gmail.com!ssmtp
	user=(-tu $sender)
}
if not{
	fd=other.server.net
	addr=other.server.net	# WHY
	user=()
}
exec /bin/upas/smtp -dah $fd $user $addr $sender $*

Then, I can do:

; upasname=seymour@gmail.com mail -s 'whatever' butts@gmail.com

and this sends a mail from seymour@gmail.com to butts@gmail.com as expected. The user allegedly needs to be set as 'seymour@gmail.com', not just 'seymour'. The other thing is connecting to an SMTPS port: to do this, you can add -t to the upas/smtp command line, and specify !ssmtp in the address.