đŸ’¾ Archived View for perplexing.space › 2020 › post-to-my-wall.gmi captured on 2021-12-03 at 14:04:38. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

POST to My Wall

2020-11-10

As I read the recent discussion¹ around gemini's lack of an HTTP POST analog I got to thinking of the potential to piggyback existing protocols that are widely adopted.

Both Titan and Dioscuri are purpose built for gemini, but it does give me pause to think of recreating analogous protocols and actions that exist in the broader web. Since gemini already tends to make great use of existing protocols like TLS and TCP I thought it might be a lark to incorporate SMTP as well.

1. Gemini and POST

E-mail is one of the best adopted internet technologies, which means plenty of folks have ready access to it. I haven't yet made it entirely painless but I think the bar for "getting something into gemini-space" is now even lower.

What I've Done

As a proof of concept I've created a public wall to which anyone can post. The entire thing is made in two parts, first an SMTP server that receives messages and second, a CGI script that publishes the most recent messages in chronological order on a single gemini page.

While currently the wall is a single page where all messages land, there's nothing really preventing pages or a hierarchy through addressing (like molly-brown's `$PATH_INFO`) and URL routing.

You can find it here.

While it isn't a full blown "application" I think there is an argument to be made for the general utility of the idea. For one thing, it occurred to me that the end result isn't that far from a barebones forum or BBS. Specifically I thought about how midnight.pub aims to create virtual spaces through the creative use of routing and addressing:

midnight.pub

On the topic of form-like submissions I find myself reluctant to over engineer gemini into an HTTP analog and instead spent some time reading RFC 6068:

RFC 6068 The 'mailto' URI Scheme

While it is imperfect for the use case it does present some ability to prompt for form-like data, consider the result of following this mailto link:

roughly form-like

For me, the result is a pre-populated email like the following:

To: example@example.com
Subject: subscribe to notifications
From: mail <mail@perplexing.space>
--text follows this line--
name: 
start date: 

How To Use It

If you are on OpenBSD you have access to the SMTP command:

smtp -s receiver.perplexing.space:2500 \
     -F your-address@example.com \
     hi@receiver.perplexing.space

Otherwise, you might use Python like this, which requires only the standard library:

import fileinput
import smtplib

smtp = smtplib.SMTP()
smtp.connect('receiver.perplexing.space', 2500)
smtp.sendmail(input('from: '),
              'hi@receiver.perplexing.space',
              ''.join(
                  (line for line in fileinput.input())
              ).encode('utf8'))
smtp.quit()

Both methods will read from standard input, which means you might pipe text from a file or your editor of choice.

A Small Excuse

It is worth mentioning that the above are really only necessary because of the non-standard port I am currently using. I haven't yet found a good way to make some clients use such a port (notably the webmail giants). I did temporarily run my SMTP server on port 25 in order to test out the soundness of the idea and found I was able to make a "post" to the wall from noted walled garden, Gmail, so I don't see any fundamental problems with the idea. The only reason I'm running on a non-standard port is because of my own reluctance to expose the application quite so widely yet. Servers with an open port 25 can get very noisy with bots and spam, which shouldn't necessarily be a problem due to the receive-only nature of the application.

Implementation

SMTP server

I did the easiest thing I could think of in order to get a listen-only SMTP server running. I hacked up an example from Twisted Network Programming Essentials (O'reilly 2013) for an SMTP server and added a SQLite database to save off received messages. This means there is no peristence within the application or the following CGI-renderer, instead all of the data is kept within a single tiny database with a single table.

CGI, served via molly-brown

The CGI script is the simpler of the two pieces, simply selecting the most recent 75 messages chronologically and formatting it with a minimum of gemtext markup:

#!/bin/sh

cat <<EOF | sqlite3 -batch $MESSAGEDB
select '20 text/gemini' || char(13) || char(10);
select '# This is a public wall' ||
       char(10) || char(10) ||
       'post to it by emailing: hi@receiver.perplexing.space via SMTP on port 2500' ||
       char(10);

with omsg as (
    select dt, content, from_addr
      from (select dt, content, from_addr from messages order by dt desc limit 75)
  order by dt asc
)
select group_concat(omsg.content || char(10) ||
                    printf("=> mailto:%s %s %s UTC",
                           omsg.from_addr,
                           omsg.from_addr,
                           datetime(dt, 'unixepoch')) || char(10),
                    (select '---------------' || char(10) || char(10)))
  from omsg;

EOF

You might ask whether writing CGI scripts in SQLite is really a good idea but I would counter: Is any of this?