User Tools

Site Tools


Receiving and sending emails with 9front

In this tutorial we're going to show how to configure on 9front IMAP and SMTP access for your SDF mailbox.

Note that for using SMTP on SDF you have to be a META, VHOST, VPM or DIALUP member.

In the course of this article we will use some uppercase variables you've got to replace appropriately for your use case:

SDF_USER	- username to login to the SDF shell
SDF_PASSWORD	- password to login to the SDF shell, it will be used for IMAP auth as well
SMTP_SECRET	- you may need to set this one up, it will be used for SMTP auth

1. Receiving

1.1 Add your password to factotum(4)

In order to access your mailbox, we store the credentials in factotum adding the appopriate key:

% echo 'key proto=pass service=imap user=SDF_USER !password=SDF_PASSWORD' \
	 > /mnt/factotum/ctl

1.2 upasfs(4)

upas/fs is used to access the remote mailbox and mounting it locally as a filesystem. If you're not running upas yet, you can launch it with:

% upas/fs -f '/imaps/'

You'll find the mailbox mounted under /mail/fs/mbox (default mailbox).

1.2.1 Non-default mailbox

If you're already using upasfs(4), the command in the previous section will most probably fail as you already have another mailbox named mbox. Of course you can have many different mailboxes, to create a separate one for SDF:

% echo open /imaps/ sdf > /mail/fs/ctl

In this scenario the SDF mailbox will be mounted under /mail/fs/sdf

See upasfs(4) for more details.

For the rest of this article we're assuming that the mailbox is mounted as the default one, and the programs we're going to use make the same assumption, however such programs accept a flag or an additional parameter to specify a different mailbox. Please consult the appropriate manual pages for more details.

1.2.2 IMAP server certificate.

The very first time you try to access with upas you'll get an error:

upas/fs: opening /imaps/ for not recognized: sha256=j1iBZLD5iPEcGYJopv9oMBHjZcZAzTsfAzj7bIXA2T4

That's because the X.509 certificate is unknown to your system; to make it trusted for the mailer just add it to the file mail inside /sys/lib/tls (most probably such file doesn't exist yet).

% echo 'x509 sha256=j1iBZLD5iPEcGYJopv9oMBHjZcZAzTsfAzj7bIXA2T4' >> /sys/lib/tls/mail

1.2.3 Namespaces considerations

If you're running upasfs(4) inside a rio's window you'll quickly find out that a fresh new window won't inherith the previously opened mbox. That's because it was mounted in a different process group and its namespace is not fully shared with every other process.

To do that, you may want run upas/fs before starting rio(1), so every window created will have /mail/fs populated.

Another way to share the mail box is launching upas/fs with the -s flag:

% upas/fs -s -f '/imaps/'

From upasfs(4)

  1. s causes fs to put itself in /srv with a name of

the form /srv/upasfs.user.

That allows you to mount back your mailbox in a separate process group running:

% mount /srv/upasfs.$user /mail/fs

1.3 Read emails

The mbox is exposed as a filesystem where each email is presented as a directory, e.g.:

% lc /mail/fs/mbox/92	
bcc		disposition	from		messageid	rawunix		subject
body		ffrom		header		mimeheader	references	to
cc		fileid		info		raw		replyto		type
date		filename	inreplyto	rawbody		sender		unixdate
digest		flags		lines		rawheader	size		unixheader

Every file in such directories contains the relative data about the email. This is a great API, because it makes very easy to write your own mail client. We could also read the email directly from the shell with something like:

% for (i in from subject body) echo $i: `{cat /mail/fs/mbox/92/$i}

But that isn't really that great, is it?

1.3.1 nedmail(1)

% mail

when mail(1) is used in this way it is just a frontend to nedmail(1).

TODO: expand.

1.3.2 faces(1)

With faces(1) we could monitor a mailbox for incoming mails.

% faces -i


It uses the plumber(4) to receive “notifications” from new emails from upasfs(4) and, right-clicking on a message, it plumbs the message so it can be displayed by another program.

1.3.3 acmemail(1)

Mail allows you to manage your mailbox directly inside acme(1)

All you have to do is launch acme:

% acme

And then run Mail. By default it will open a new window /mail/fs/mbox where you can edit and read your mailbox.

Right-clicking on a message id will open the message in a new window.

Put in the mailbox context is used to save any changes to upasfs(4), for instance the read status of a message.

Managing mailbox using acme(1)

See acme(1) if you're not familiar with it and acmemail(1) for more details.

2. Sending

As mentioned in the intro, you need a META, VHOST, VPM or DIALUP membership to send emails through SDF.

See for the official details.

2.1 SDF SMTP configuration from 9front

To setup the SDF SMTP from 9front you can use vt(1) and ssh(1):

% vt
% ssh

Then on the SDF shell:

sdf$ setdialup

 [p]  Set your DIALUP and SMTP Auth password
 [m]  Toggle email address
 [n]  Set your connection type to NETWORK PPP (default)
 [s]  Set your connection type to SHELL
 [t]  Set your connection to TIP
 [r]  REMOVE your DIALUP Membership
 [q]  QUIT


At this prompt you should choose [p] to set your SMTP secret and then [m] to enable the email address.

2.2 rewrite(6)

/mail/lib/rewrite is used in order to convert a given email destination to a command to properly send the email.

By default rewrite doesn't contain any rules, for our purpose we could just use the template provided by rewrite.gateway

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

See rewrite(6) for more details.

2.3 /mail/lib/remotemail

This script is used by /mail/lib/qmail to dispose of a remote message.

We can edit it in order to hardcode smtp(8) so use SDF SMTP server:

fd=`{/bin/upas/aliasmail -f $sender}
case *.*
case *
exec /bin/upas/smtp -d -u -a -h $fd $addr $sender $*

make sure to have a newline at the end of this file, or your emails will not send.

2.3.1 Avoid to overwrite defaults

In a shared system changing /mail/lib/* files may not be ideal, an alternative way to do that is creating a $home/lib/mail directory and make there the changes we described, finally use bind(1) to replace the global one just inside our namespace:

% bind -b $user/lib/main /mail/lib

See bind(1) for more info.

2.4 Add your SMTP secret to factotum

Similarly at what we did in 1.1 for IMAP, we're adding our credentials in factotum to access SDF SMTP server.

% echo 'key proto=cram !password=SMTP_SECRET' \
	> /mnt/factotum/ctl

Note that the proto in this case is cram and the username, as mentionened in the SDF FAQ, is sligthly different than usual.

2.5 SMTP server certificate.

As the SMTP server is, we can just copy the cert we used for IMAP (see 1.2.2):

% cp /sys/lib/tls/mail /sys/lib/tls/smtp

2.6 Post email

Now we're almost ready to send emails from 9front using SDF!

2.6.1 Correct From field

With the setup described in this article you're going to send emails with From set to $ Unless you're really (oh, hi!) or in general $user doesn't match SDF_USER, please be sure to have the upasname env variable set to SDF_USER:

% upasname=SDF_USER

You may want to set this inside $home/lib/profile to prevent any error.

2.6.1 mail(1)

The simplest way to send an email is:

% echo 'this is a test' | mail -s test

when mail(1) is used in this way it is just a frontend to marshal(1).

2.6.2 acmemail(1)

Mail, already introduced in 1.3.3. could also be used to compose and send emails directly from acme(1)

You can start composing a new email middle-clicking Mail in the mailbox window: a new window will be opened, fill the email in and finally middle-click Post to send it.

Composing an email using acme(1)

2.7 Troubleshooting

% tail -f /sys/log/smtp
% tail -f /sys/log/
playground/email_with_9front.txt · Last modified: 2021/04/26 08:10 by gall0ws