Hacker News new | past | comments | ask | show | jobs | submit login
Unverified.email (kerestey.net)
237 points by vitplister on April 8, 2020 | hide | past | favorite | 63 comments



> we can create a mailbox via HTTP GET request to 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)


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)


Considering this is relating to an API, the mention of whether to use GET or another method implies a REST API, in which case GET is described as:

> safe, meaning that applying it to a resource does not result in a state change of the resource (read-only semantics)

It should never be used to -create- anything, only to retrieve existing resources (and not change their state). For creating we have POST requests. Obviously no one is going to care or do anything about it if you use GET, but if we're going to be pedantic le t's not mischaracterise GET requests.


Not quite. GET is defined to be "safe" and "idempotent", and while "safe" does mostly mean "no side effects", it actually means something more like "doesn't cause harm" per-RFC7231:

   Request methods are considered "safe" if their
   defined semantics are essentially read-only; i.e.,
   the client does not request, and does not expect,
   any state change on the origin server as a result
   of applying a safe method to a target resource.
   Likewise, reasonable use of a safe method is not
   expected to cause any harm, loss of property, or
   unusual burden on the origin server.
  
   This definition of safe methods does not prevent
   an implementation from including behavior that is
   potentially harmful, that is not entirely read-only,
   or that causes side effects while invoking a safe
   method.  What is important, however, is that the
   client did not request that additional behavior and
   cannot be held accountable for it.  For example, most
   servers append request information to access log files
   at the completion of every response, regardless of the
   method, and that is considered safe even though the
   log storage might become full and crash the server.
   Likewise, a safe request initiated by selecting an
   advertisement on the Web will often have the side
   effect of charging an advertising account.
  
   Of the request methods defined by this specification,
   the GET, HEAD, OPTIONS, and TRACE methods are defined
   to be safe.
https://tools.ietf.org/html/rfc7231#section-4.2.1


I think that is being pedantic. No-one's going to misunderstand what the intended idempotency of GET is supposed to be.


This may tip the pedantry scale too far, but the comment you are replying to is in reply to a comment that suggests confusion over the idempotency of GET.

I'm not suggesting that it's named wrong or anything like that, this is just about your comment.


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


PILLAGE was too long, so we use GET.


That's how URL shorteners work.


If all the API calls create a mailbox on demand, and never return a "mailbox doesn't exist" error, then the GET doesn't make any observable changes - it's as if the mailbox has always existed.


Provided that there aren't any other consequences, such as emails not being delivered before you do that GET.


Idempotent != no side effects.

Idempotent == if you do it more than once, you get the same result.


It using a GET does mean that when you lick on the link it actually works - which is kind of neat although not strictly RESTful (but then nothing ever is).


In this case, it generates a new resource; ideal for one-off e-mail addresses. If you do a GET on most websites you get a different result as well, e.g. the news has updated or in the case of HN the comments or news order has changed.


There is a difference between „getting a different result“ and „making the result different“. You mean the first one whale the mentioned site does the latter one. The first one is Ok, the second one not.

A subsequent GET may return different data because another POST/PUT modified the data but a GET should never modify the data itself (e.g. i won‘t be able to safe this comment by GET but by POST).


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.


I think a relatively easy one, if the author was interested in securing this more, would be to strengthen the requirement around the "mailbox id". Specifically require it in a single header, like how it's done in the example. That way, you could set up your own tests to match expectations, but it would be useless to use to abuse another third party (as the site that you're attempting to verify on certainly won't send that header).


> 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.


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.


It's an alternative to mailhog or mailcatcher so no email is actually sent. It's just for testing sent emails.


You can still retrieve messages sent to the service, and use it to signup to whatever web sites you want. Verification links are trivial to extract from it.

That it doesn't actually relay mail doesn't hinder its spam potential.


It doesn’t receive email. It doesn’t have an email address. It’s an SMTP server. No third party will ever route an email to it.


MX server of @unverified.email matches the ip of smtp.unverified.email

It would appear that it is configured to receive email sent to @unverified.email


Huh you’re right. That seems kind of counter to the purpose here, but I guess the intent was you can email {mailbox_id}@unverified.email


If a service is relying on "must have an e-mail address elsewhere" as a gate for users signing up, then there are so many trivial workarounds that this is a minor drop in the bucket.

I don't think there's any obligation to try to make that work, nor how allowing people to do so is in any way harmful.


From a personal opinion standpoint, I agree with your latter statement. I don't block throwaway email domains from my services.

The few times I've hosted something like this (previously running open source https://gitlab.com/markbeeson/maildrop), it just never ends well.

What typically happens is abuse reports start rolling in for mass forum spam, mass registration, comment spam, domains get blacklisted and added to global blacklists like URIBL.

Over time as bad actors found it, I eventually was doing more than 50-80 Mbps of _purely text traffic_ of bots flooding registrations, inbound SMTP traffic of nothing but spam, bots effectively sending DoS-level requests looking for activation links. It was frustrating to want to run something fun and inevitably end up spending half your day responding to "this is a development/testing INBOUND ONLY mail service, we did not originate the spam, we are not signing up 5000 times to your forum", adding a domain blacklist to never show messages from certain websites, etc.


Also, if you host this sort of thing on a public cloud instance, it poisons the IP for the unfortunate souls who get it after you release it back into the pool. I once had to troubleshoot why email notifications from a server of mine didn't work, and turns out the IP was already on several blacklists when it was assigned to me.


I guess it will be added to a blacklist but does it really matter? The service will continue to work for the purpose it was built for.


How is this different from the million other services that provide the same thing, like Guerrilla Mail? Just as with these other services, if you're intent on not letting users sign up with disposable email addresses (and you shouldn't be), then you just block the unverified.email domain in your signup form.


Came here to mention Guerrilla Mail as well -- I'm using it with end-to-end tests successfully, but it can be slow (~30 seconds for an email to be available). I believe it's slow because it's popular, so I imagine this will happen to unverified.email as well.

But I'm curious about your statement:

> if you're intent on not letting users sign up with disposable email addresses (and you shouldn't be)

Why not? It seems like some people are eager to not be on any mailing lists, and the worst downside seems to be that they won't able to reset their password.

Yahoo.com et al. are still available to create one-off emails to allow someone to get past a (say) 14-day free trial every 14 days, so how does blocking these guys help?


"Why not? It seems like some people are eager to not be on any mailing lists, and the worst downside seems to be that they won't able to reset their password."

I think you missed his double-negative there - he is saying that you shouldn't not be letting users sign up with ...

... which I agree with ...


You may be right... alas, I seem to be able to parse his sentence either way. Stupid NLP :-)


> Yahoo.com et al. are still available to create one-off emails to allow someone to get past a (say) 14-day free trial every 14 days, so how does blocking these guys help?

Yahoo requires SMS verification on every signup.


Ah, thanks for the update. Glad they're using such a secure, unhackable technique /s


rsync is right - I missed the ambiguity in my sentence.


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?


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 [1] https://gauge.org [2] https://taiko.dev


I'm not huge on mocks, but I usually just mock out an email service (which has been manually tested) - that is, I don't test it end-to-end. Everything apart from the actual sending is tested though, such as testing that the email subject and body that would be sent are as expected.

In the past I've also used a local test SMTP server, similar to the service in the article, but much more basic (I forget the name of it now).


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.


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....


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


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


Why not use Twilio for this?


Mailinator does this (you can get a private SMS to API)


Shameless plug: I've made a similar service with both an API and a web interface at: https://mailspons.com/


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".)


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?


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!


I think the point is that this is testing your MTA, not his. I.e., if you're connecting directly to unverified.email, you're not really testing whatever your app uses for outbound.

Afaict, this isn't a forwarder, just a mailbox endpoint.


There's also https://ethereal.email/ which has a Web GUI.


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/ [1]: https://mailcatcher.me/


>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?


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


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.


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


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.


God forbid it be regex!


I really don’t like this part. Having to include this ID means that there’s something extra needs to be done in tests. And the tests become not so real anymore.


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


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.


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.


Mailtrap, which is listed as an alternative Ruby library, is also available as a service: https://mailtrap.io/


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




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: