HN user

craigmccaskill

451 karma

Product and systems guy. I like talking to people. Recovering designer/developer.

Originally from Scotland, transplanted to the SF Bay area for a few years.

hn[at]username.com

Posts4
Comments115
View on HN

Yeah, those are similar but narrower scope tools. They do one thing, sit behind a firewall, listen on port 25 and forward SMTP submissions to sendgrid/mailgun's endpoint using an API key.

Posthorn adds an HTTP form endpoint (which is safe to expose to the internet), a JSON API with Bearer auth and idempotency, and a provider abstraction so you can use a broad range of providers via config.

If you just need to forward SMTP requests behind a firewall to a single provider, those are far simpler solutions and Posthorn is overkill. The moment you need anything outside of that, I couldn't find a solution that worked and that's the gap I built Posthorn to fill.

Happy to take any feedback on my approach, either here or in GitHub issues.

No, Posthorn is outbound only. DMARC aggregate reports come back as inbound mail to whatever address you put in your rua tag and Posthorn has no inbox or IMAP to receive them.

Parsedmarc is still the right tool if you want to self host reporting, otherwise you should look into solving this with your provider. Explicitly trying to avoid dealing with all the operational costs of running a mail server, just trying to enable email capabilities in apps that need it so it's beyond the scope of what I built here.

If I'm understanding it right, protonmail-bridge exposes an IMAP and SMTP interface to your local mail client so that if you want to use something like Outlook or Apple Mail to talk to ProtonMail you can.

Similar idea in that it receives SMTP and transforms it to a provider specific API but it's unique for the ProtonMail use case of bridging to your personal mail client and it handles both sending (SMTP) and receiving (IMAP).

Posthorn is server side and outbound only. It runs in your stack and enables apps to send email that otherwise can't. It fronts multiple transactional providers via config and doesn't touch inbound at all.

Awesome. This is helpful, thanks. You're doing my market research for me!

Seems like most setups only really need 2-3 channels, rather than the ~140 supported by Apprise. Definitely worth me looking into when I start to work towards a v2 release and supporting webhooks in general.

The part I'm not sure about yet is how I'm going to implement it. My current approach is to custom write a transport layer for each provider, so a generic webhook would be the first non-bespoke transport. I don't want to lock myself into the path of writing a bespoke solution for every email provider and every channel (that's basically reimplementing Apprise in Go with better email support). I'm hoping I can get a generic webhook that would be good enough for most use cases.

I'll also need to think about if I want to support an email + webhook use case or pick one per request. If I built that and you deployed it for email + telegram, would that be good enough for your use case? You could also just deploy it alongside Apprise if you have an email need that we handle better (and I think we definitely do, especially once I ship html email in 1.x).

If you do end up using Posthorn, please let me know how it goes and feel free to open up any issues you see on GitHub.

Yeah, this is a good point I should probably make a bigger deal out of in the documentation. I also have it automated with docker compose/ansible so it just deploys with the apps that need it and starts working.

Let me know how it works out for you, happy to help in any way I can. Also feel free to make any feature requests or open an issue on GitHub.

If I just wanted to enable a few services I'd use AWS or whatever

But then you'd be using AWS for those services too.

I think there's a meaningful gap between folks who are willing and able to self host their own applications but have decided that running their own MTA is a separate and much harder commitment. Different line, but still self-hosting in any reasonable read of the term. I've been on both sides of that line at one point, I'm trying to avoid going back. :)

Nice. Sounds like a neat way to get the best of all worlds. Self hosted email without exposing your IP, leverage a third party with an existing trusted send reputation but still maintain full ownership of the stack.

How much effort has it been to keep it running? Glad that it works for you!

Haven't used Apprise, but it looks interesting!

My current plans are for Posthorn to stay focused on email. There's enough work here that I think it justifies a dedicated tool.

I have some v2 roadmap ideas for things like multiple outputs per endpoint so that a contact form submission can fire both an email and a webhook in the same call to support things like form -> email + slack or script triggers an email + pager duty alert.

That's complimentary to the email though, not something I had planned to build out as a stand alone use case. I'd be interested in hearing how that would be useful for you though!

Fair. Don't disagree with anything you're saying here.

I should probably tighten up that line. What I really meant to say is that the average self-hoster who just wants to enable a few services to send email doesn't want to run a mail server. Different audiences, different (and both correct) answers.

I set out to solve some pretty specific problems of my own but I'm genuinely curious how others have tackled these things. Posthorn and Postal don't compete in my head. Postal makes you into your own provider, which is something I personally deeply want to avoid. Posthorn assumes you've already picked a provider (which might be Postal, actually, it would work just fine pointed at a self-hosted Postal instance).

Two things to unpack here:

1) Posthorn doesn't host email - no inbox, no IMAP so it doesn't replace what it sounds like all-inkl is doing for you. All it does is take the outgoing messages from any of your hosted/local apps and take care of the plumbing of handing them off to a transactional provider (like Resend or Postmark). Those servers are the ones sending the mail, using their IPs and their sending reputation. Any blacklist concern is really tied to your sending domain and not a new risk from Posthorn. Just the same setup you'd do if you were calling something like Resend directly. If you're following their guidelines, you'll be fine.

2) On the VPS side, if your goal is to be able to ssh in, install some stuff and run your own services, something like Hetzner is a well regarded EU centric option with solid technical support baked in. Security is mostly on you and down to what you install and how you configure it. That can be a huge learning curve and a whole other kettle of fish, definitely not without risk.

Nullmailer's a good call for a single-app use case. It's basically what I was doing.

Posthorn ended up the way it did because I had three different things all hitting Resend at the same time: a contact form, a couple of apps that only had SMTP email support and some scripts I wanted to email results from. I didn't want to have to maintain three different things doing functionally the same routing. Putting them in one binary helped me consolidate credentials and logs.

You're not wrong about the split though, I thought about breaking the two out. I'd originally written the http form handler as a caddy module (which I called caddy-formward to be cute) but ultimately I went the other way because the code after the ingress is the same regardless of how you come into the service and I didn't want to rewrite all that logic.

Have you encountered a similar issue with multiple apps where nullmailer hasn't been enough? Curious how you handled it if so.

Correct, but not all apps can talk directly to an HTTPS API. Ghost, Gitea, Mastodon, NextCloud, Authentik, Matrix to name a few all only have built in SMTP support. Posthorn listens for that connection from those apps locally and translates it into whatever your transactional mail provider needs.

If all the apps you're running can already integrate via HTTPS API, Posthorn doesn't solve anything for you in that case, unless the unified credential, single retry policy and logging meaningfully simplifies things for you.

And honestly, SES was the easiest integration for me to write (even if it ended up being the most LOC), their documentation, examples and error responses gave me a really easy time setting it up. Additionally, because it does need such a verbose implementation SES ends up being a great case study for Posthorn and not needing to maintain the same 200 line signing routine in multiple different places.

Personal mail is the one case I think where hosting your own MTA still makes sense when you want to own the addresses and the data. You still have to solve for deliverability, which is something I hope to never have to do.

Posthorn is built for the opposite end of that, you've already decided you want to use a transactional provider for app mail and you just want to stop having to deal with wiring it into all of the things. Obviously for a big production app you build your own mail service, but for gluing together a bunch of different apps you're self hosting, I think this makes sense and addresses a real issue.

If you want an API piece to augment what you already have, Posthorn might still be useful regardless of how the rest of your mail is set up. A Posthorn JSON endpoint is just a POST with Bearer auth and an idempotency key. Example from my docs:

curl -X POST https://posthorn.yourdomain.com/api/transactional \ -H "Authorization: Bearer $WORKER_KEY_PRIMARY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: reset:user-123:$(date -u +%FT%H)" \ --data '{ "to_override": "bob@example.com", "subject_line": "Reset your password", "message": "Click here: https://app.example.com/reset/abc" }'

Could run alongside your existing mail server. It's a small enough overhead that the juice might be worth the squeeze.

This is really cool. I'll be checking it out!

Seems to solve most of my issues with my current workflow. My primary personal development machine is my WSL ubuntu install on my windows gaming PC and the tooling outside of the mac ecosystem has been really limited.

Outside of the day job (PM at an enterprise SaaS company), I've been building an AI-native CLI for Todoist [1]. Started to solve a personal problem, automating action item extraction from my Obsidian notes, but it's become something bigger. The CLI treats both humans and AI agents as first-class users: TTY-aware output, a schema command for agent discovery, idempotent operations, that kind of thing.

It's been a great excuse to get back to my roots as an engineer and lean into some of the newnew with Claude Code. Learning a ton, having a blast, and also enabling being (marginally) more productive with my actual work day to day.

[1] https://github.com/craigmccaskill/todoist-cli/

Disclosure: I'm a PM at ServiceNow. Opinions my own.

High. SoR systems tend to either be where or are closely tied to wherever the work is being done. It's an incredibly disruptive thing to rip out and change all of the process and backend systems that run your business. It's why land and expand is such an effective strategy for these companies and everything is sold as an interconnected economy of scale.

I'm quite a bit more bullish than OP, but I would be lying if I said I wasn't worried about the way the market has reacted and the 'new multiple' trend.

There is always going to be a market for a business operating system, we just might be a similar situation to Netflix/HBO last decade, where the race was about which side could shore up their core weakness first: content engine vs. streaming platform.

We're seeing the same thing happen now. Enterprise has the data, business logic, customer base and distribution but it needs to add SotA AI capabilities into the core of the product without just bolting something on. The Ai companies have the models, talent and are agile enough they can turn out demos and compelling pitches abut they're missing the enterprise data, domain specificity and being able to operate with the regulatory and compliance scaffolding that is required to operate in the enterprise.

Both sides are racing toward the middle, but the problems left for the AI companies to solve are arguably the harder ones, especially when the models themselves are rapidly commoditizing or are open source. It's tough to build enterprise-grade infrastructure on top of a layer where your core differentiation is eroding.

There was another comment in this thread about value moving to the agent layer. I'd push back a little on this. An agent is only useful if it has reliable, governed access to the system where the work actually happens. The SoR that builds a credible agent platform on top of its own data and workflow layer has a structural advantage over a standalone agent tryin to orchestrate across five different systems via an API. IMO the strong foundation wins out here.

That’s not really fair. I mean, I definitely use AI all over the place, but I think that the writing aspect is an important part of thinking too [1]. I still try to write things out myself when it matters. There’s something about wordsmithing that sharpens your thinking and that gets lost when you just drop something into an LLM and pull it out without much thought. Sure, I’ll use AI to help refine or explore ideas, but the core work often starts in my own head.

I do write a lot myself, especially when I need to think something through clearly. I use AI tools like anyone else, but I still do the work.

[1] https://craigmccaskill.com/writing-is-still-thinking

They have their place but I'm really just trying to avoid the AI house style that has emerged. I'd rather have my writing—AI-assisted or not—reflect how I actually communicate rather than defaulting to patterns that have become over represented in generated text.

You can just add it to your master prompt. I have this added to mine, YMMV:

Tone & Communication Style

* Keep it clear, structured, and concise.

* Maintain a professional tone but make it feel natural and human; avoid robotic or overly formal language.

* Use a more conversational tone in casual, mentoring, or internal team contexts.

* Do not use em-dashes or emoji unless specifically requested.

Fair, don't think I disagree with you on these points. I just believe we can do significantly better. In a similar vein, I believe:

* For profit motives get in the way of cheap, effective healthcare. Maximizing shareholder value leads to higher prices, overutilization of expensive proceedures and prioritization of profit generating services vs. preventive care or basic health care needs and improved outcomes.

* Incentives are currently heavily skewed to the point that providers and insurers are more likely to treat symptoms rather than address root causes or preventive measures leading to a cycle of chronic illness and higher long term costs.

* Access to healthcare should not be tied to socioeconomic status. Employer sponsored insurance and high out of pocket costs create significant barriers for lower income individuals and families, dragging the average down (i.e. the system is fine if you can afford it).

* Administrative complexity in the current system massively inflates cost. The fragmented nature of private insurers, billing systems and out of network shenanigans results in massive inefficiencies and expenses that contribute nothing to patient outcomes. I am confident this comes out to more in savings than the %age profit that is referenced in other places in this thread.

Agree that it's not perfect, but I do feel that we could take 60-80% of the money we're currently spending and fix this and any other issues that come up and get in the way of improved outcomes like the rest of the world does.

I don't know why what you're describing happens, but my money would be on some triage that needs to happen due to limited funding since so much of our spending goes into private healthcare solutions.

Kaiser had an income of 4.1B in 2023 vs. UHG's 371.6B in an industry of 4.8T [1]. I'm not sure the point you're trying to make or why it's relevant unless you're asking me to read between the lines on the efficacy of Kaiser as a non-profit vs. their for-profit counterparts (which is what seems to be the case).

edit: I think I missed the last part of your comment in an edit, so to attempt to answer my own questions, it's not a fair comparison beyond just the almost 100x size difference to compare a different business model and scope, provider network, risk pool and geographic presence yet ignore every other developed country in the world and say that for profit is the way to go because if Kaiser can't do it then nobody can.

[1] https://www.reuters.com/business/healthcare-pharmaceuticals/....

If there is a silver bullet, the first step would be getting rid of the for profit mechanisms.

Instead, because despite data linked in this thread that profit margins are only a few percentage points, Healthcare is an incredibly lucrative field that extracts a lot of money into the private market without delivering results commensurate with the cost to the public.

Add to that lobbying making it incredibly simple and cost effective to influence policy (which comes out in the P&L as a cost of doing business and so isn't tracked as profit FWIW), we are stuck with this situation despite overwhelming evidence that it's a bad deal.

The same statistics are similar for Medicaid too but also missing the forest for the trees in that for profit seems to be the main differentiator with the US vs. other parts of the world. There are plenty of models around the world that show this works and it works well.

First it's the government can't do this, then it's the government wouldn't do this because of this reason while ignoring that the US healthcare system is spending more than any other country and missing the mark on outcomes. Every other developed country in the world has figured this out. While not perfect, they're paying less and broadly getting better outcomes.

But has everything to do with the need to take a closer look at the entire system and how we can do things better.

I feel like focusing on this part of my comment vs. the bum deal part is disingenuous since non-US countries have figured out how to do it for cheaper with better outcomes without the main focus being the up and to the left drive for profit that our current system mandates.

Medicare administrative costs are around 2% of total program spending [1] compared to typically >10%. While what you're saying on the surface may be true from the numbers you are comparing, the fact of the matter is that healthcare costs are becoming more and more expensive during a time when many are experiencing a cost of living crisis.

The US gets a bum deal on costs and outcomes and while we can argue on which specific changes will move which specific needle I think it's clear that one of the major differences compared to the rest of the world is that running healthcare as a for profit enterprise has failed to deliver on the promise of good outcomes for as affordable a price as possible both on an individual and country wide level.

[1] https://www.politifact.com/factchecks/2017/sep/20/bernie-san...