
Unverified.email - vitplister
https://kerestey.net/writing/2020-04-05-announcing-unverified-dot-email.html
======
afraca
> we can create a mailbox via HTTP GET request to
> [https://api.unverified.email/create](https://api.unverified.email/create)

Shouldn't GETs be idempotent? (Sorry for not having feedback on the idea,
skimming it it seems nice, though there is fierce competition as others have
shown here)

~~~
mike_d
No. GET is defined to be nullipotent, or having no side effects. That is not
the same as "not making a change."

To be pedantic, every GET request to a modern website makes a state change
somewhere... to a log file, to a database, to a tracking system. The
difference is it has no side effect for the user (i.e. your comment gets
duplicated or your order placed twice)

~~~
cyansmoker
Not being pedantic, then, but is GET even the right verb to create a resource?

~~~
de_watcher
PILLAGE was too long, so we use GET.

------
dylz
What kind of anti-abuse mechanisms do you have in play?

As soon as the API is figured out, it'll be used for mass spam signups. I've
done one of these before, and pretty much if you allow any form of being able
to retrieve a code or URL or number from the body/subject, it'll be used for
millions of spam signups.

~~~
thanksforfish
> create a mailbox via HTTP GET request

I'd suggest a POST here. Theres some extra web browser checks against sending
cross origin POSTs that GETs don't have. The GET makes abuse easier.

~~~
zedr
GET can also be cached by intermediate proxies. This can cause failures that
are very hard to troubleshoot. POST cannot be cached and therefore is more
suited to this type of action.

------
umaar
Nice work. I investigated a few similar services, mailtrap, mailgun,
mailosaur. I wanted to try having my end-to-end tests assert that the email
which got sent out actually included the correct info. (As in, you request a
password reset to test@emailtesting.tld, and then you make API calls to assert
the email exists and includes the correct text)

It works well for peace of mind as it gave me a high degree of confidence that
I'm testing almost exactly what the end-user would experience. However, it
does add 5-10 seconds of delay to your tests while polling the email inbox, it
can be a little expensive depending on your test frequency, I think there are
even some cases where you can hurt your email deliverability stats during
automated email sending.

In the end, I decided to keep this test manual which I run every now and then
only after making big changes. Instead integration tests which mock the email
service are probably enough for my use case.

Curious how do others test the end-to-end behaviour of their web application,
when it comes to emailing?

~~~
chris_st
I'm doing an application backed by AWS's Amplify, and so I _have_ to have a
service that gets the email with the confirmation code.

I'm using Guerrilla Mail[0] for that, and it works, but it's slow to receive
the email and make it available.

I'm using gauge[1] with taiko[2] to write the tests, and liking it a lot, even
though I never liked cucumber. taiko is just very reliable, and the test
support code is much nicer to write.

[0] [https://www.guerrillamail.com](https://www.guerrillamail.com) [1]
[https://gauge.org](https://gauge.org) [2]
[https://taiko.dev](https://taiko.dev)

------
stephenr
Having more open source software is always good, so congrats on putting
something out there.

I'm very curious why this takes the approach it appears to take: running two
docker containers with opensmtpd in one of them, and then scanning the maildir
for message content; compared to what the numerous existing solutions
(mailcatcher, mailtrap, mailhog, maildump) all do: run an in-process SMTP
server.

~~~
rooam-dev
My guess is that it's a simpler approach. Maildir stores messages in files, so
persistence out of the box.

Meanwhile [https://thehackernews.com/2020/01/openbsd-opensmtpd-
hacking....](https://thehackernews.com/2020/01/openbsd-opensmtpd-hacking.html)

------
tzs
I use a simple local catch-all SMTP server for testing. I install it on my
test machine listening on some non-SMTP port (default is 2000), and then use
iptables to make all connection attempts to port 25 end up at the catch-all
server.

Here's the iptable command: "iptables -t nat -A OUTPUT -p tcp --dport 25 -j
REDIRECT --to-port 2000"

The catch-all server is ridiculously simple. It just responds with a "220
hello" when connected to, and then just reads input line by line, logging all
input to a file. It only knows about two SMTP commands: DATA and QUIT.

On QUIT it sends "221 bye" and closes the connection.

On DATA it sends "354 send the message" and then just reads the data and logs
it to the file.

Anything else? It just sends "250 OK".

Note that this is pretty useless if what you are trying to test is a mail
client, because you cannot test error cases. The purpose of this SMTP catch-
all is for testing the content of messages your software sends, not for
testing the process of mailing itself.

Each connection is logged to a separate file.

The source is a single Java file. Here it is if anyone wants it [1]. "javac
SmtpSink.java" to compile. "java SmtpSink" to run. Messages are stored in the
"msgs" directory, which you should make before running it.

[1] [https://pastebin.com/WqkS7jNH](https://pastebin.com/WqkS7jNH)

------
DeathArrow
I'd like to see an analogous service for SMS: I. e. provide a new phone
number.

~~~
borski
Why not use Twilio for this?

------
dbfa
Shameless plug: I've made a similar service with both an API and a web
interface at: [https://mailspons.com/](https://mailspons.com/)

------
jlgaddis
If, by chance,the author happens to see the comments here... you may consider
choosing an alternate (high-numbered / "unprivileged") port -- say, 2525? --
and redirecting connections to that port to 25/TCP on the same host.

This can be easily accomplished with a single iptables / nftables / pf / etc.
rule.

(A non-insignificant number of ISPs, CSPs, etc., block outbound connections to
25/TCP by default -- except, in some cases, those going to to their own mail
servers or "smarthosts".)

~~~
bscphil
If they're blocking SMTP, doesn't it make sense to block the encrypted ports
too, e.g. 587? But if they're blocking 587, then how do people with these ISPs
use their own email clients like Outlook (or whatever it's called these days)
with third party email providers, e.g. Gmail?

~~~
jlgaddis
25/TCP is, technically, for MTA <-> MTA traffic, so many (residential, in
particular) ISPs block it because "you shouldn't be running servers".

587/TCP is the "submission" port and is exactly what people _should_ be using
instead of 25/TCP (it usually -- but not always -- requires authentication and
is pretty much never blocked). Indeed, that's the intended purpose!

------
vince14
There's also [https://ethereal.email/](https://ethereal.email/) which has a
Web GUI.

------
PersonalOps
See also Mailslurper [0] and Mailcatcher [1] if you'd like to self-host an
email catch-all service.

Mailslurper appears to be abandoned and seems to be missing deterministic
builds that go module support provides.

Mailcatcher has been around for a while, with my first discovering it being
used in a legacy project's test suite back in 2014.

Both could use some better SEO since it's nearly impossible to find unless you
know exactly the right keywords to use.

[0]: [http://mailslurper.com/](http://mailslurper.com/) [1]:
[https://mailcatcher.me/](https://mailcatcher.me/)

------
rosstex
>The mailbox_id from the above setup should be included somewhere in the text
of the email, the subject, the bcc address, the headers, or any other field
(even email address of the sender or recipient will do).

Sorry... how does it know what mailbox id to look for?

~~~
phnofive
The mailbox_id can be anywhere in any field you send, apparently.

~~~
rosstex
No no, but... nowhere in the PUT request is there a mailbox ID. In fact the
PUT doesn't contain any token from the mailbox creation. So how does it link
your email without searching for every mailbox ID that currently exists within
your email? I mean, maybe that's how it works, since they expire in a fairly
short amount of time... seems ripe for DDoSing.

~~~
lilyball
The ids follow a set format, so it probably scans the email for all strings of
that format, then looks them up against a dictionary of existing mailbox ids

~~~
lilyball
I may be wrong. I’m not the strongest with Haskell, but skimming the code, it
appears to just dump all incoming email into the same dir and when you receive
on a mailbox it scans the directory for any files containing the mailbox id.
I’m not sure what code goes through and cleans up old emails though.

Edit: it used a cron job that runs every minute and used `find` to delete any
file that’s 5 minutes old. This both cleans up emails and deleted mailbox ids.

This is a rather simple way to do this but you could just dump a massive
amount of email on the service and it’ll run really slowly for the next 5
minutes.

------
kccqzy
Mailinator is a much more well-known service. It has both a web interface and
an API.

~~~
fredoliveira
For perspective (and I'm not affiliated with this new service, or really,
anyone in this space): at some point, Altavista was more well-known that
Google.

------
jeffrallen
If your testing system depends on a remote server, it's not testing just your
code anymore. Tests must be as isolated from other changes as possible or else
they do not tell you anything.

------
franky47
Mailtrap, which is listed as an alternative Ruby library, is also available as
a service: [https://mailtrap.io/](https://mailtrap.io/)

------
7ewis
Could the JSON return info like SPF/DKIM too passes too?

