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