How to use HELO with PHP’s mail() function

I originally wrote this for the HELO-community tracker, and it was subsequently published on BeyondCode’s blog, but I wanted to publish it here as well.


HELO works very nicely if you’re sending via SMTP using PHPMailer, SwiftMailer, etc. – but lots of apps and scripts rely on PHP’s clunky old mail() function, which isn’t nearly as easy to deal with, and harder to point at HELO.

You can configure “proper” mail servers like postfix to work as a local relay, but it’s horribly complicated and confusing to set up. Fortunately there are simpler alternatives that are much easier. Searching for local relay tools (what this is) will usually point you at ssmtp, however, that doesn’t work on macOS. A better option for macOS is msmtp which is present in homebrew and works perfectly. I usually run HELO on localhost port 2500, and I configure msmtp with a config file like this, which enables the authentication that HELO requires:

defaults host localhost port 2500 tls off undisclosed_recipients off account default auth plain user test password password

To make the PHP mail function use msmtp, you need to configure the sendmail_path setting in your php.ini file to point at it:

sendmail_path = /usr/local/bin/msmtp -t -i

If you’re using homebrew’s PHP package on macOS, I recommend putting config changes like this in a separate .ini file so that it remains update-safe. For example I put mine in /usr/local/etc/php/7.4/conf.d/marcus.ini.

With those two things in place, PHP’s mail function will submit to the local msmtp binary, which will then relay the message to HELO over SMTP.


Sending via this this route using PHPMailer is very simple because mail() is the default mailer, so you don’t need to configure anything:

<?php use PHPMailer\PHPMailer\PHPMailer; require 'vendor/autoload.php'; $mail = new PHPMailer(); $mail->setFrom('from@example.com', 'First Last'); $mail->addAddress('whoto@example.com', 'John Doe'); $mail->Subject = 'Say Hello to HELO'; $mail->Body = '<h1>Hi!</h1><p>This is my HTML body</p>' $mail->AltBody = 'This is a plain-text message body'; if (!$mail->send()) { echo 'Mailer Error: ' . $mail->ErrorInfo; } else { echo 'Message sent!'; }

The Stack Overflow Antipattern, part 2

I enjoyed Riggraz’s observation of “The Stack Overflow Antipattern”, and it made me think of another very similar pattern that I see a lot on Stack Overflow, but it occurs after the pattern that Riccardo describes, and I thought I’d outline that here.

Image by wal_172619 from Pixabay

I answer a lot of questions on Stack Overflow. I ask very few, but I’ve still fallen into this trap myself.

Once you’ve been through Riccardo’s antipattern (ignoring the other antipattern of those that don’t even make it to step 1), you are here:

  1. You’ve searched and found some random results
  2. You’ve read some SO questions that were in those results
  3. You’ve still not found a solution

If you’ve got this far, the breadth of the question you want answering has probably been narrowed a little (which helps in its own right: searching is a mild form of rubber ducking), and probably contains the basis of a worthwhile Stack Overflow question.

So you focus on the problem, write it up, and (assuming this rubber-duck exercise didn’t lead you to a solution) post the question, and answers and comments appear reasonably quickly (hey, Stack Overflow rocks!). But often these responses are bogus, half-answers, or raise further questions. It’s at this point that we see the same “not taking the time to think” that Riccardo observed. You are so focused on the original question, you become incapable of solving a far simpler follow-on question.

Here’s a small example I often see:

“I’ve seen docs and code referring to autoload.php, but I can’t find that file”

Searching for autoload.php will find a zillion irrelevant results, because pretty much every PHP project in existence has one. So the question is posted on SO. There is a simple answer to this question, which is

“install composer, run `composer install`, and it will create the autoload.php file for you”

This inevitably leads to the follow-on question:

how do I install composer?”.

This is a new sub-problem, but one that is instantly solvable by searching because it’s far less ambiguous. However, this is where the abdication of thinking kicks in, and rather than actually doing that search, you ask in the SO question comments, and sit around waiting for an answer from Someone Who Knows™ that posted an answer to the original question. This is frustrating for the answerer, who knows that the asker could find the answer to this question far faster by searching for themselves, but they choose not to because their thinking is turned off. There’s also an element of panic – the asker has obtained the attention of someone capable of understanding their problem, and doesn’t want them to escape before they have addressed the full recursive stack of sub-problems. This has led to the existence of passive-aggressive responses like LMGTFY, which are demeaning and condescending, but reflect the frustrations of those who answer questions.

What’s weirder is that I have observed myself doing this very thing, and I’ve sometimes had to stop myself posting trivial follow-up questions without thinking. Avoiding having to think is evidently a compelling driver.

I emailed Riccardo about his article with some of the thoughts that led me to write this, and he came back with another interesting observation: This loss of confidence that leads one to post trivial follow-up questions is very much like imposter syndrome. Having had to ask a question in the first place can provoke feelings of embarrassment or inadequacy, and anyone that responds in a positive way will appear to be in some way superior, which is fully expected, but at the same time provokes feelings of “we’re not worthy”, further reducing one’s confidence to be able to deal with even simple problems.

We’re not worthy

I know that Stack Overflow (and GitHub issues) can sometimes be harsh on new users, and old hands (like me) can forget what it’s like to be a beginner. It can be very frustrating to answer questions that have been answered many times before (“my PHP script just gives a white screen”), and I’ve occasionally found myself editing my initial reaction to avoid unkindness. In those situations I usually try to overcompensate by offering more general advice about how to avoid getting stuck in dead-end situations like that, rather than just answering the precise question asked.

In PHPMailer I have tried to head off support questions before they arise by adding links to documentation in error messages, but it doesn’t stop people posting questions like this:

I have this error:
> 2020-05-16 07:28:11 SMTP connect() failed.
> https://github.com/PHPMailer/PHPMailer/wiki/Troubleshooting

I have been stuck on this for 2 weeks, and I searched the entire internet three times
Where can I find out how to fix it? You must help me urgently!

I don’t really know what to do when faced with this. Posting a substantive answer is probably pointless – if they have not read what’s right in front of them despite their evident frustration, chances are they will not read any answer you post either, especially since it will only contain exactly what’s in the link provided anyway. Sometimes the best thing to do is vote to close the question, usually as an inevitable duplicate. I see very similar things happening in GitHub issue templates – askers delete the boilerplate text, removing something which would usually help them solve their exact problem in a few seconds, but they go out of their way to make the process take longer and involve others unnecessarily, because apparently not having to think is a more attractive proposition.

I’ve also considered pushing in the other direction, such as by adding “delete this line from the debug output before posting questions about it, or your question will be ignored” as a way of enforcing reading the error messages, but that’s unkind.

I’m not sure how to address the abdication of thinking issue though. Perhaps offer up search results derived from comments or answers, much in the same way that Stack Overflow does when you first post a question? There are probably extensive psychological studies on this pattern of behaviour, and it may well have a name, but that’s a question for another Stack Exchange site.

Abstraction as a service

This is a short story I wrote back in 2015 and published on Medium. I don’t want to use Medium any more, so I’m reposting it here. If you like it, please follow me on Twitter.


On a warm, drizzly London day, I’m looking out of a window for inspiration. I can see a building from my window that an old client moved into recently, and I’ve watched them gradually redecorate it with their own branding. By the ground floor entrance is a small shop that appears to sell nothing but Aero bars (in milk chocolate or mint).

That thought makes me hungry, so I head out for lunch.

In a busy sandwich bar I bump into Claire and we chat about work between mouthfuls of an excellent sandwich (though I don’t recall what was in it). She mentions that she knows someone who might need my services, and who might turn up here for lunch.

A little later she points out a guy who’s just come in. Apparently his name is Tris. He’s 40s, slightly foppish, baggy-looking in a dark linen suit, like something from Muji. He seems distracted.

She waves at him. I’m not sure if he sees her.

We finish our lunch. Claire leads me over to Tris, says a brief hello and introduces me. It seems Claire has mentioned me to him before. “I hear you do the kind of thing I need” says Tris.

I reply with a hesitant “Yes”, not knowing what it is he needs.

He’s there with his daughter, who’s talking to someone else. She’s about 15, with short, dark hair and a denim jacket. I don’t catch her name. She glances at me, smiles, and returns to her conversation.

Tris says we should chat about some work he needs doing. He’s heading off on a sales trip to Taipei and Buffalo, NY, and needs some stuff doing pretty much immediately. He suggests we go to his office.

We head to the station. It’s packed with a glazed post-lunch crowd. We hustle onto a train; hot, humid and smelly. Standing close in the carriage, I notice he’s carrying a shoulder bag the same colour as his suit, a large white book and a handful of pencils. The pencils all have coloured tops, but I realise they are all graphite pencils of different hardnesses, and the points are worn down to fat, blunt stubs; he’s been busy. He sees me looking, and shows me the book; It’s a “grown up” colouring book, but old and worn. He flicks through a few pages in the limited space and I see a mix of repeating patterns and odd artworks, most partly but meticulously coloured in with shades of grey. He complains that it’s a bit cumbersome; one drawing folds out across multiple pages showing a mole digging through earth filled with jumbled aeroplanes, cars, skyscrapers, Coke cans. I have a fleeting moment of recognition; I’m sure I had this book back in the 80s, but I preferred it left as black and white lines.

We arrive at a station. He says suddenly “this is us”, hurriedly bundles up the unfolded page and we explode gently onto the platform in a spray of commuters.

By the time he’s sorted himself out, the station is empty. We cross to another platform and board an empty, old-style train with compartments. It smells dusty. His daughter slumps onto the old bench seat in a cloud of dust and plays with her phone.

The train lurches and bumps down the track to wherever. Tris is animated — he’s got a new concept that he’s bursting to pitch to his foreign clients, though he doesn’t go into detail. He suddenly stops and looks at me pointedly. “You know about 400?”

I’m floored for a moment, but venture “You mean like the HTTP error code?”

“No, no. Do you know about customer databases?”

“Yes”, I say, somewhat relieved.

“OK then, you’ll be fine”. He fiddles with his phone for a moment then hands it to me. “Give me your contact details”

I fill in his contacts app and hand it back. “That’s great, thanks” he says.

We arrive at a station, apparently ours, so we all alight. The rain has stopped. Just by the station is a newsagent. An aluminium-framed frosted glass door next to it sports a small plaque: “Tristan Enterprises”. I hope his daughter is not named Isolde. We go through the door, climb a narrow stairway and emerge into a small office. It’s almost empty, very tidy, and everything is completely white. An old white MacBook sits on one of two desks. I wonder if he only uses it because it’s white. He hangs his bag on a hook, dumps the book on the desk next to the laptop.

“I need servers”, says Tris, “to run all this stuff”, he says with a wave encompassing the entire empty office.

“OK”, I say, “I can do that”.

“Excellent. I think that covers it. I’ll be in touch with the details. Are you alright getting back?”

“Er, I guess so”, I say, mystified that he should bring me all this way for so little.

I head home though the muggy afternoon wondering if it’s all been a waste of time. By the time I’m home, he’s emailed me with login details of his cloud provider, asks me to commission a few servers. I log in and see it’s much as I expected, so I set things up and email him back.

That was a few months ago now. It turns out Claire is working for Tris now too, so we quite often meet for lunch.

We’re happy that Tris pays the bills, but we still have no idea what he does.

Using a Behringer DSP8024 for Room EQ

I have a Behringer DSP8024 Ultra-Curve Pro audio processor on the output of my computer.

Behringer DSP8024 audio processor

I picked up this relatively ancient unit for £50 about 15 years ago (it cost about $500 back in 2001!), and they can still be found on eBay, along with later models like the DEQ2496, and related hardware like Focusrite’s (discontinued) VRMBox. It provides many different audio processing functions, including:

  • Stereo 31-band ⅓-octave graphic equaliser
  • Real-time stereo 31-band spectrum analyser
  • Stereo 6-band parametric equaliser
  • Delay up to 2.5 sec
  • Noise gate
  • Automatic “feedback destroyer”
  • Accurate level meter with selectable scales
  • “Brick wall” limiter for output protection
  • Automatic room equalization using microphone input and internal noise generators

It’s this last feature that is the most useful, combining the analyser with the graphic equaliser. Room equalisation (EQ) can correct a lot of acoustic deficiencies in a room. The shape, composition, and contents of a room, and non-linearities in your speakers and audio interface all contribute to how audio sounds within it. Ideally you want to minimise these effects so as to hear as true a signal as possible. It’s a good idea to apply corrective EQ after adding simple physical acoustic controls (e.g. absorber panels, diffusers, and bass traps, or just old duvets and cushions). Room EQ gets some criticism from audiophiles because it can be very hit & miss and can’t address bigger issues, but it can work very well if you listen from a single location in your room (e.g. in front of your desk).

To measure the room equalisation accurately, you need a microphone with a flat (or at least well-documented) frequency response; I use a t.bone MM-1 for this.

The t.bone MM-1 measurement microphone

The equalisation process works like this, starting from flat EQ (no alteration):

  • Output pink noise from the unit through the speakers
  • Analyse what it sounds like through the microphone, from your usual listening position
  • Alter the equalisation towards a flat response
  • Iterate over this process until the overall response is as flat as possible

This process is loud and quite unpleasant, so leave the room or stick on some closed headphones while it’s busy! It takes a minute or so, and you can hear the change in characteristic of the noise playing through the speakers, and see the changes in EQ on the screen of the unit during the process. After it’s done you can save the EQ curves, and switch the EQ in and out to A/B the config. The difference is pretty noticeable, particularly at the low end where most room-related acoustic problems tend to be; overall it’s like having a major speaker upgrade! One benefit I really notice is when switching between my corrected speakers and a decent pair of monitoring headphones – the audio really doesn’t change in character; there’s no significant tonal shift between the two.

Some people have noted problems with “digital noise” when using this unit, particularly at low volume levels. I suffered from this for a long time, but then realised what caused it and solved the problem. If you have a volume control that is before the processor, you will end up with a small signal going through the analogue to digital converters (ADCs), effectively throwing away much of their available resolution, and you’ll get a lot of quantization noise as a result. The best way to hear this deliberately is turn the input level down, and the output level up, then play something smooth and quiet. It will sound horrible, gritty and noisy, you can really “hear the bits”. This isn’t a problem unique to this unit – any ADC provided with insufficient signal will suffer the same problem.

You want to maximise the use of ADC resolution by giving it a full-range signal to convert. So if you have an audio interface before it, make sure it’s turned up full, and if you have any software level control (e.g. macOS system volume), make sure that’s turned up full too, so you’re always sending a full-volume signal. This way the converters will always use their full 24-bit resolution and the quantization noise will be so small you won’t hear it (it’s impossible to remove completely). However, you still want to control your output level. There are 2 ways to do this: alter the level on your monitors (which can be inconvenient as volume controls on active monitors are often on each speaker separately, and often hidden around the back) or use a passive volume control between the equaliser and the speakers. I use a Mackie Big Knob Passive for this.

A Mackie “Big Knob” passive volume controller.

Passive volume controls have no power supply (so no noise or extra cables), and can only turn a signal down, not up. It’s analogue, so there are no DACs or ADCs, just simple passive components. Ideally when it’s turned up full, it should be indistinguishable (acoustically speaking) from a length of cable.

Controlling level directly on the speakers (or on a separate amplifier if you have one) is possibly better than this approach, but usually less convenient. If you want to be able to run your speakers at full volume via the passive volume control, you need to have the monitors turned up full, and this often means you’ll get significant analogue noise (hiss) from the speakers when you’re listening at lower volume, however, that’s generally less unpleasant and not the problem we’re addressing here.

All of this attention to correct signal levels throughout an audio signal path is part of a wider concept known as gain staging, and occurs in many other places in audio recording, processing, mixing, mastering, etc.

It is possible to do all this processing in software using systems like REW or RoomEq, or even to go further and emulate other listening environments, famous studios or speakers, but I quite like having all this externalised and independent of software, and it also means that it can be applied to external inputs too, if you’re playing an instrument directly through a mixer. The “big knob” also provides a very convenient single control for output level, along with other features such as mute/dim and speaker and input switching.