Thanks for the patience, something you did with this, so stay tuned for Markets, who I see
a crew watch because they are not to give the final tour of today's one of the
first of all, I'm Markets, this is where I live, I took this photo last month, I described
myself as a skier, songwriter, and I'm also the maintainer of PHP Mailer, which
she may have used at some point. PHP Mailer is completely crazy, I have 95 million downloads
and 20,000 GitHub stars and nearly 10,000 forks, which is insane. But I write songs about web development,
I think it's important to list these things because in these days of AI, AI lacks personality
and I want to have more of that. So I always run into this problem of how to test a
offline, obviously I have a meltdown and it needs to collect lots of things and it needs to cope
when things don't work properly. So PHP Mailer really gave you the motivation to do this, but
really it's hard to test things and as a result I've found that my test suite is really concentrating
on things like the fact that these calling these methods doesn't fail but not necessarily really
testing what happens at the other end of things. Now in order to test it properly, you really
want to configure a mail server and send something to it and see what happens. But servers are hard
to configure, especially if you're trying to make them go wrong. Doing mocks are painful and not
necessarily very representative and they're a maintenance burden. So do we really need another
mail server? Well, the existing ones are hard to configure even if you want them to do stuff
right. And if you want them to do bad things, it's even more difficult. It's even harder if you want
them to do multiple bad things. So in this time including things like post-fixxm,
send mail and send mail is notorious for the complexity and complete unreadability of
its config files. So how about we make a mail server that generates errors on demand?
Well, I discovered actually yesterday that Apache James does actually have partial
ability to do this. However, the thing I had some other ideas in mind so this is why
I wrote Bad S and T P which is the reliably unreliable mail server. So it's unreliable.
You can depend on it to be unreliable is the key thing. So what do we mean by this?
We want to be able to get errors without having to configure anything is the number one thing that I
wanted to be able to achieve. And the thing that was the realization was that it was actually
possible to do this by driving the error configuration from the client, not the server.
By sneaking things through the SMTP protocol without breaking it. We can generate errors from
different places. I wanted it to be small and completely self-contained so that you can just
drop it into a CI system and that it should just work without you having to configure anything.
It runs as non-privileged user on high number ports so we don't have to have root access or anything.
And it guarantees that it's not going to deliver your messages. So it's really unreliable.
And this is really just so that you can be sure that stuff isn't going to escape to your
real clients and so on. You don't think what things sneaking out of your development or CI environments.
So these are the kind of different times that were different places where things can go wrong
in a mail server, the initial TCP connection, TLS, hand shakes and certificates, exchanges.
The list of capabilities that the server actually has, you want to send something that's set that's
UTF8 and you find that the server doesn't support it. What are you going to do?
Authentication, lots of ways that can go wrong.
Addressing, you know, you might be trying to send to a user that doesn't exist.
But you really don't want to have to configure a mail server to have or have not have users to find.
Then when it comes to actually sending the message, there's lots of ways that can go wrong too.
You know, you can send a message it's too big that contains content they don't like or any other number of things.
And there are lots about other SMTP operations which you can issue commands for that might go wrong in some time.
For example, any SMTP command can get a 41 error because the server is decided to close down.
So on the TCP side, what I did was I've defined some port ranges.
This allows you to have things go wrong or act in certain ways that might be difficult to configure on a real mail server.
In particular, getting it to do a greeting delay that's controlled by the client.
So here, what I originally did is I actually had that the last three digits were the number of seconds that it was going to wait.
But then I realized that this would leave me to having like 3,000 ports open on the server.
It just didn't seem like a great idea.
So the it opens 10 ports, which are at 0, 1, 2, 8, 10, 30, 60, 120, and 300, and 600 seconds delays.
So you can choose from, like an exponentially increasing list of options.
600 is important because that's the time out for most SMTP commands.
Similarly, you can figure it to allow it to open the connection, but then it just randomly drops it after a certain period of time.
And it uses the same delays for those.
TLSR is, well, I've set up ports 25, 4, 6, 5, 5, 8, 7, 4, the two ways that we can do implicit or explicit SMTLS.
But the main thing to hear really is that I didn't go into a great deal of depth on this because one of the things that inspired me to write it in the first place was badssl.com.
If you go and look at that page, it's also an open sort of project.
It has lots and lots of configurations for all different ways that TLS can go wrong.
And some of those things are usable from SMTP.
So you can just simply configure your mail client to point at those examples.
For example, they have an endpoint called expired.badssl.com, which presents an expired certificate, which means you don't have to go and try and configure one yourself.
Now, one of the key things really is that we wanted to be able to control how the server behaves.
Now, when you go alone normally, you give it the hope you're a hostname.
But I figured that's just a parameter.
We can sneak other things through there.
Now, obviously, the one of this downside of doing this is that no, it's not going to kick you out if you're a reverse DNS doesn't resolve.
We're just ignoring that.
But it'll accept any hostname you like.
But the main thing is that the first part of it, you can put in one or more things that allow you to configure the availability on unavailability or set some values of how the server is going to behave.
So we can say that we want to turn off authentication altogether.
So author won't appear on the capability list.
Similarly, we can knock out SNTP UTFA.
We can override the size setting.
We can impose a delay between commands.
And this is all configured in the allow hostname string.
And you can just keep adding them up until you run out of space.
Now, one slide problem here is there's a 63 character length on the label within a hostname.
But on the whole weekend, live with that.
If you need to do more than one thing, then just do it on a separate connection with the different set of parameters.
The delay lets you go up to 605 seconds, which is just over the limit, so you can see if you're your email client that behaves properly.
When it comes to authentication, because we, I don't really want to have to configure any users or anything.
I've just made two very simple things.
But if the username contains good auth, it will pass.
If it contains bad auth, it will fail.
The users don't exist.
There are no user accounts.
And it doesn't pay any particular attention to any of these implementations.
It just lets you use them and you can pass in these values, and it will either fail or succeed.
But basically, it's just lying, but that doesn't matter.
It's good enough as far as your mail client is concerned.
I told you it was unreliable.
About the first thing that I thought of when I was thinking about building this.
I've been thinking of this for like the last three years or something.
I've finally got ran through it after I'm here,
provoked me into doing something about it.
So we use the mail from command as the primary place where you can set up ways that the service is going to go wrong.
And you can use that particular point there to trigger things going wrong with the mail command itself.
So here, if I do mail 449 as the local part of the address that's going to try and send from,
this will immediately trigger a 449 response.
So we use the client to configure how the service is going to behave.
And this means that things are really simple from the server point of view.
You don't have to do anything.
You just go, when I say do this, do that.
And then it does and you don't have to configure anything.
We don't have to make sure that this, you know,
going to making that error happen for real would be really annoyingly difficult.
So we can just get the server to just serve you the error message because that's all you actually want.
We can then do per recipient errors, whether the RCPT commands.
And it also supports the 234 enhanced codes,
where you can do the, so we get us BD 550 and then underscore and then the enhanced code you want.
The reason I left the dots in this format rather than just squeezing them together like this,
is that some of these numbers now have actually got as far as putting three digits in the third part of this.
I've come across something which is like 5.7.110 or something like that,
which is like a demark thing from Yahoo, something peculiar like that.
So these things exist. It does support pipe lining.
After a certain point, the pipe lining is a little bit fragile, the way that it works,
but it means that some commands can overlap kind of slightly,
but you tricky thing in SNTP.
Then when it comes to actually sending the message, it supports data and BDAC.
I didn't even know this existed.
I've seen chunking in the capability list, but I didn't actually know what it meant.
And then I discovered that it's all about this BDAC thing that lets you specify things.
It means that you don't have to do dot stuffing and relying on the dot on our line by itself to end the message.
You can just give it a proper message length,
and it's a nice way of avoiding problems with that.
Because I've had, for example, Microsoft Exchange, like not doing dot stuffing and wrapping properly and things like that.
You can specify errors in the mail from that occur later on in the conversation.
So if I do a data 451, when it actually comes to sending the message,
the data command will fail with a 451 error.
And the reason I have to do that is that the data command doesn't take parameters,
so I don't get the opportunity to do it there.
But I can schedule it in advance from the mail from.
And I can do that from other commands as well.
So for example, silly things like reset and no up,
you can make them generate errors as well.
Just you just tack on whatever error you want, you can make it here.
If you tell it to do a 41, it will actually kill the connection as well.
So it is a real 41.
Yeah.
So on the by default, it just throws away all the messages.
This is very much like SMTP sync, which is part of postfix.
SMTP sync is really focused on performance testing for SMTP.
It does allow you to do some of the same kind of things like you can set it to,
to put delays between commands and also to return some error codes.
But you have to configure that on the server side, which makes it much less convenient,
and certainly not the kind of thing you necessarily want to drive from CI.
But you can just configure it so you give it a path, and it makes,
it just puts any non-error generating message into that path.
But it uses the mail-dear format so that you can connect it up with other tools like iMac servers
or email clients that read that format.
So you can easily just run,
doff got something in the same server and use that to look at the results of your tests.
Looking, it writes regular structured logs to this log on standard outs in JSON.
It automatically reduces credentials in case you've used your real credentials in your testing environment.
Because this is for testing, we really don't care what the credentials really are.
We just want to know whether it will pass or fail.
Configuration, why I said, it has sensible defaults so you can just use it out of the box with that configuring anything at all.
You literally pull the binary, run it, and that's it.
There's no other setup required.
But you can override certain things, for example, if you want to change the ports for this,
listening on, then you need to do that from config,
and it allows you to set the configuration from environment variables from CI-lic switches
or from config files in yamoldjson.n formats.
Implementation wise, my background is all PHP,
and this was the first time I built something to go, and goes quite different.
But I decided to try and keep it all modern since it was new.
So it's written in go, 1.25, and the tests are also run against the 1.26 nightly builds.
I tried to use standard go libraries wherever possible, so the basic SMTP protocol support is using the text
protocol library, which is designed for building protocols like that without a lot of the standard overhead,
that you might, if you were doing it from scratch.
Minimal external dependencies are only really too co-brand,
therefore reading from config files and processing command line options.
I also wanted to be able to use this in other ways.
And so I provided hook points at various places in the server itself.
And these are triggered whenever something interesting happens, like you trigger an error or you receive a message or open a connection or whatever it is.
But by default the server doesn't do anything with that information, it's just the hook is just there.
But what you can do is take the source code of the server and write an extension for it,
which essentially wraps around it and then compiles into a new version of the server,
which then does whatever it is you want the extension to do.
And my purpose for doing that is that I'm writing like a hosted version of this,
and I wanted it to be able to talk to an API, so I've written the larval application that provides a user-facing thing,
so I've got mailboxes and test results and things like that.
And to make the mail server talk to that I've just written an extension for it, which is not open source,
but it lets me talk to my API directly.
And it's really quite a straightforward thing to do.
I'm not a go-person and then I didn't find it that difficult.
But I deliberately tried putting there was the ability to actually create brand new SMTP verbs.
I just thought people might be trying out weird things and seemed like a perfectly reasonable thing to use to test it with.
So if you don't have to do strange things with SMTP then this might be the place to do it.
Anyway, I have a SMTP playground here with a terminal window with a bunch of buttons that allow me to just issue SMTP commands into the connection.
I think we're taking Q&A and people can come up to you.
Yeah, you can come up with your free to come and have a look.
Maybe let's do it as a Q&A first.
Thank you very much, first.
Thank you.
Thank you very much.
Is domain name significant or do you just use the website for magic?
But everything on the right hand side of the app, you can...
Oh, sorry.
Is the domain name significant in any of the places where you might have a domain name like in the LO and in a mail from and so on?
No.
It absolutely does not care.
It doesn't do any checks, it doesn't do reverse DNS.
It doesn't even look up the name.
The thing I said about being limited to six new characters, that's true if it was actually going to look at up in DNS.
But in fact, it doesn't.
So you can probably actually do it longer.
I have just hadn't tried.
Can you?
Yes, check.
Test.
Do you want to?
Because it's for some reason, it's complicated.
Okay, other things I can't test yet.
Well, imagine the TLS side of things I haven't really gone into in any great detail because that's really covered better by things like by a bad SSL.
One of the things that I'd say that it doesn't do at the moment, I was like, I really concentrated on this ability to generate errors.
But that was kind of it slightly at the expense of actually making it behave properly as an SNTP server.
So it does enforce some things, but it may not be very thorough in terms of compliance.
So for example, it doesn't let you do an RCPT2 after that sort of before a mail from.
You can't do a data unless you've done both of them.
So there is a little state machine in there that keeps state, but and you can do things like reset and that does go back to the right points and so.
But there are probably places in there where it doesn't quite work.
Actually, I'll put this back up there because we're now as well.
Yeah, so this is my to-do list.
There are more interesting areas you could do.
You could come up with probably better go than I've written.
We can do moral authentication types like NTLM if you need that.
You can add all the SNTP commands through extensions.
We could probably have better test coverage.
And I said this thing I just mentioned was better compliance with SNTP spec.
And the thing that I'm trying to do as well, which is turned it into a hosted service.
And that's essentially it.
There is a site for it.
Badness in tp.com.
I got that domain.
I was very happy about that.
I got the quick Twitter handle and the GitHub org as well.
So that will take you to the GitHub repo.
And this will take you to my blog where you can buy my music and listen to my songs.
And offer me a job.
Anyway, that's all.
Thank you very much.