Please enable JavaScript to view the comments powered by Disqus.

Teddy Hartanto

thoughts and experiments

Email is a core communication channel we rely on at Hozuko, Singapore's direct-landlord property rental platform. We primarily send transactional emails, not marketing emails. This write-up evaluates email providers from that perspective.

Here are some popular options:

  1. Amazon Simple Email Service (Amazon SES)
  2. Postmark
  3. Resend
  4. SendGrid
  5. Mailgun

Initially, I assumed these services were more or less the same—so I didn’t think my choice would matter much.

  • Amazon SES: Cheap and reportedly reliable. I’ve only used it briefly. I generally avoid Amazon tools due to their clunky UI/UX.
  • Postmark: Frequently recommended on Reddit and tech blogs.
  • SendGrid: I’ve used it before at Ninja Van, but I wanted to try something different.
  • Resend: Founded in 2023. As a newer player, I was cautious—new companies often face growing pains that mature ones have already solved. That’s just a rule of thumb, of course.
  • Mailgun: I picked it because an engineer I admire uses it. I assumed it’d be a safe bet.

Oh boy, was I wrong.

I had a horrible experience with Mailgun.


TL;DR: I had serious deliverability issues with Mailgun. Support took 2–3 weeks to respond, claimed they fixed the problem (they hadn’t), and pushed me to upgrade. I upgraded—still broken. I filed another ticket and waited again. Eventually, I switched to Postmark and had a flawless experience. Here’s what happened.


Comparing Postmark to Mailgun

Email Open Tracking

Before the deliverability issues, I encountered a peculiar problem with Mailgun’s open tracking: every email was marked as “opened” just one second after delivery.

Their response:

This can happen due to antivirus software, spam filters, or email clients that auto-open messages. We recommend using tags to view unique opens.

Fair enough. I implemented a workaround to ignore instant open events.

After switching to Postmark—no such issue.

IP Reputation

Checked via SenderScore:

  • Postmark: 97
  • Mailgun: 13

Postmark separates transactional IPs from bulk email pools. Mailgun doesn’t. I was repeatedly assigned low-reputation IPs that caused Microsoft to block my emails.

When I raised this with Mailgun, their excuse was:

There will always be risks associated with shared IPs... think of it like a highway: multiple drivers share the risk of its use, but still choose to use it in order to benefit.

I can’t justify using a dedicated IP—I don’t send enough volume, nor do I have the capacity to manage it.

Meanwhile, Postmark just worked.

Email Logs

  • Postmark $15/mo plan: 45-day retention
  • Mailgun $15/mo plan: 1-day retention

UI/UX

  • Postmark: Clean, modern, and intuitive
  • Mailgun: Dated and clunky

Customer Support

  • Postmark: I haven’t needed support—because nothing has broken
  • Mailgun: Slow, vague, and ultimately unhelpful

Conclusion

I can’t speak for every email provider—but I can confidently compare the two I’ve used.

❌ Don’t use Mailgun:

  • Poor IP reputation = frequent deliverability issues (especially with Microsoft)
  • Support is slow, indirect, and upsells without resolving issues
  • Misleading communication
  • Minimal log retention
  • Outdated interface
  • Wasted weeks of my time

✅ Use Postmark:

  • Excellent deliverability
  • Great IP reputation
  • Better UI/UX
  • No issues so far—everything just works

If you’re sending transactional emails in 2025, skip the frustration.
Go straight to Postmark.


Which one do you think will make you money?

  • A good solution to a bad problem, or
  • A bad solution to a good problem

My answer: ✅ A bad solution to a good problem


How We're Conditioned

In school, we're taught to solve problems—not to find them.

Instead of learning to... we were told to...
figure out what equation is worth solving solve the equation given
choose a topic that matters to us write an essay on a predefined topic
define what we truly want to learn follow a fixed curriculum

We weren’t trained to ask questions or identify meaningful problems. At least, not in my school. The problems were handed to me—I just became a highly trained monkey, skilled at solving neatly packaged, well-defined tasks.

Then comes real life.

Suddenly, we're in an unstructured world. It’s messy, complex. There are thousands of problems all around. Which should we solve? In what order? School never taught us that. It trained us to find good solutions—but it’s finding the right problem that actually matters.

If there's one thing I've learned—through life and through building a business—it’s this:

Solving a problem is relatively easy. It's finding the right problem that's hard.

Answers are everywhere. You have Google. You have ChatGPT. What matters most is asking the right question.


Employee vs Entrepreneur

As an employee—especially in an individual contributor role—your world resembles school. Your company gives you problems. You solve them.

Running a business is different. The key isn’t solving problems—it’s finding good ones.

In business, it’s better to have a bad solution in a good problem space than a perfect solution in a bad one.

  • A good problem space has high demand and a large market. Even if your first solution is rough, you can improve it over time and gain traction.
  • A bad problem space has low demand, a tiny market, or intense competition. You might perfect your solution—and still go nowhere.

The problem space is the limiter. Find a good one. Follow the market.


This insight had been sitting in the back of my mind for a while. But when I saw Michia Rohrssen mention it, it jolted me. I had to quickly write this down—to burn the lesson into my brain.


I haven't talked much about this, but I've been building Hozuko, Singapore's direct-landlord property rental platform. I'll share more about that in future posts.

For now, I need to vent:

I had a horrible experience with Mailgun.


TL;DR: I had an email deliverability problem. Their customer service took 2-3 weeks to reply and claimed that they'd fixed my problem when they didn't. They even asked me to upgrade my plan. I upgraded, and that did nothing. The problem is still there. I filed another ticket. It's been 2 weeks, and there's no news. Screw Mailgun. I'll switch to Postmark.


It's been over a year since I wrote the first line of code for Hozuko. If there's one thing I've learned, it's this:

Building a great product is extremely hard.

Every part of the system has to fit together perfectly—like a well-oiled machine—for the whole thing to work. It's even harder when you're going solo. But that's the challenge I chose. I want to prove to myself (and the world) that this can be done alone.

Part of what makes product-building so hard is choosing the right vendors—auth providers, email services, analytics platforms, etc. There are dozens of ways to accomplish any goal, and there is no shortage of tools that claim to be the best.

Take auth providers, for example:

  • Supabase
  • Firebase
  • Next Auth
  • WorkOS
  • Kinde
  • Clerk
  • SuperTokens
  • Hanko
  • Ory
  • Lucia auth
  • Build-your-own
  • and more...

On paper, they all seem similar. Feature checklists look the same. But when you actually use them, the differences are night and day. Some are just plain bad.

Here's the analogy I now live by when evaluating vendors:

Choosing a vendor is like hiring a chef. Every chef claims to be able to make spaghetti, fried rice, and pudding on their resumes. But only when you taste their cooking do you realize some of them break spaghetti in half before boiling it or make fried rice using freshly cooked rice. It's the same with software vendors. The devil is in the details.


Mailgun: The Chef Who Can’t Cook

Let me walk you through what happened with Mailgun.

📅 6 Mar 2025

I noticed emails to @live.com and @hotmail.com were failing. I opened a support ticket:

My emails to addresses on domain @live.com or @hotmail.com are failing. Could you please advice how can we fix this? Pasting the email metadata below.

Mailgun returned, asking me to verify my business and describe my email practices. After I answer all those questions, they'll assign Hozuko a shared IP pool with a higher reputation.

📅 7 Mar 2025

I replied that the verification form was inaccessible, but I explained how we use email at Hozuko.

📅 8 Mar 2025

They said they’d escalate the ticket to another team.

📅 13 Mar 2025

I followed up. No response.

📅 17 Mar 2025

I followed up. No response.

📅 25 Mar 2025 — finally a reply:

Hello Teddy,

Thank you for contacting Sinch Mailgun Support.

After reviewing the currently assigned IP, it appears that a problematic sender led to the IP's listing on a reputable blocklist. While we work to delist this IP, we have reassigned your sending to a new IP.

You are currently on our free plan which is a very limited plan that is only for basic testing.

It took 12 business days to tell me this.

📅 27 Mar 2025

Emails to Microsoft inboxes were still failing.

I replied:

I'm still running into the same issue. What do you need from me so that I can be on the shared IP pool with a higher reputation as X previously mentioned? If I need to be on the paid pricing plan for that, that's no problem. Just let me know. I can only commit to the basic plan as of now though looking at the volume of our emails.

📅 28 Mar 2025

Their response:

As mentioned in the previous email, we will need your account to be on a paid plan in order to proceed. The current plan you are on is intended solely for testing purposes. Once you have completed the upgrade, please let us know, and we will be more than happy to assist you further!

But here’s the thing: they never clearly said I needed to upgrade. If they did, it was buried between the lines.

Anyway—I upgraded to the 10K basic plan and asked for help again.

Their reply? Exactly the same message as before:

“Your IP was blocklisted, we’ve reassigned it.”

📅 4 Apr 2025

Emails still weren’t working. I filed yet another ticket.

Their reply:

Thank you for contacting Sinch Mailgun Support.

After reviewing the ticket, it has been determined that we will need to engage another group of colleagues.

We are transferring the ticket to them, and they will be responding as soon as possible.

📅 19 Apr 2025

Still no response.

That’s it.

I’m done.

I’m moving to Postmark.

Screw Mailgun.


Nevermind ditching MySQL. Traccar recommends not using the embedded H2 database for production

It's interesting that we need to run the following to secure the MySQL server:

sudo mysql_secure_installation

What happens if we don't?

teddy@debian-2cpu-2mem-sin-1:~$ sudo mysql_secure_installation 

Securing the MySQL server deployment.

Enter password for user root: 
The 'validate_password' component is installed on the server.
The subsequent steps will run with the existing configuration
of the component.
Using existing password for root.

Estimated strength of the password: 100 
Change the password for root ? ((Press y|Y for Yes, any other key for No) : Y

New password: 

Re-enter new password: 

Estimated strength of the password: 100 
Do you wish to continue with the password provided?(Press y|Y for Yes, any other key for No) : Y
By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : Y
Success.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : Y
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : Y
 - Dropping test database...
Success.

 - Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : Y
Success.

All done! 

It seems that the default MySQL installation configuration allows anonymous users login and remote root login.

References [1] https://docs.vultr.com/how-to-install-mysql-on-debian-12


I previously chose to run MySQL because of the added challenge of managing it. I love challenges. However, it has become a burden because not only do I need to set it up when I have a new VPS, but also it consumes a lot of memory and I don't need that. I now prefer to keep things simple.

Funnily enough, by choosing to keep things simple, I'm making things a bit challenging for myself yet again. I've spun a new VPS on Hetzner and got a Writefreely instance up. Next is figuring out how to restore the data.

When I migrated from AWS->DO, I dumped the MySQL DB from AWS and restored it into DO. That's not possible now that we're changing the SQL engine. Luckily, I found mysql2sqlite. A savior!

It wasn't a smooth process because that tool is old and there were some INSERT statements that contain binary values as such:

INSERT INTO `table` VALUES (1,_binary '<BINARY>',_binary '<BINARY>');

So, I just dump the posts table:

sudo mysqldump --skip-extended-insert --no-create-info --compact writefreely posts > dump_$(date -u +"%Y-%m-%d_%H%M%S")_posts-only.sql

Convert it into sqlite format:

./mysql2sqlite dump_2025-01-01_085842_posts-only.sql | pbcopy

Then run the INSERT statements against the sqlite3 DB in my Hetzner VPS.

Voila! We're back in business.


My parents are getting old. They sometimes forget where they place their belongings: wallets, debit cards, phones. Sometimes, their phones are actually somewhere out in the world. Other times, they just misplaced their phones somewhere inside the house. In either cases, we're all panic-stricken.


This is where I come in. I'm the technophile. Let's solve this using tech.

Not long ago, a friend told me about Life 360, a location sharing app. The idea is that I can install that app on my parents' phones and keep track of their locations.

But, the issue is that it asks for phone numbers. I don't like that. I went looking for alternatives and found two names in this space: 1. Owntracks 2. Traccar

Upon reading reviews, I've decided to try out Traccar.


Next, I need to host the Traccar server somewhere. Hosting it on the same server as the blog seems like a no-brainer. After all, who reads my blog? 😂🥹

Anyways, my blog was running on a 1vCPU 1GB memory DigitalOcean droplet with 25GB SSD. It costs me $6/mo. Here's the resource utilization: – CPU is ~1-2% most of the time. Never crossed 10%. – Disk usage is 26% – Memory sits at ~75% though. A whopping 46% was used for MySQL server.

It's obvious that the MySQL server need to go. But, even so, I'm not sure if the resources are enough for Traccar.


I found a good deal on Hetzner: 2vCPU, 2GB Mem, 40GB SSD at a price tag of $9.25/mo. It's not an apple-to-apple comparison, but the cheapest 2vCPU 2GB Mem DigitalOcean droplet comes with a price tag of $18/mo. I compared the prices of both VPS providers in case I needed an upgrade. It seems to me that Hetzner is cheaper.

Price wasn't the only reason I decided to migrate to Hetzner though: 1. It was just nice that Hetzner expanded into Singapore this year 2. I want to get a taste of Hetzner. DigitalOcean's log in page takes a long time to load 3. Migrating the systems would be a nice challenge during this lull period in my life. I need a challenge.

With all that, here's the plan: 1. Spin up a Hetzner VPS 2. Migrate my blog from DO –> Hetzner 3. Install Traccar


I wanted to also try out Coolify. Check out the intro video. But, let's do things the hard way now. I want to learn more about nginx so instead of having Coolify abstract the nitty gritty details away, I'd like to dive deep into the technicalities.


I hiked Mt Batur in Bali a few days ago, and I heard an eye-opening anecdote. When my hiking guide, Kadek Bagawata, showed up, I was surprised. He was topless, barefoot, and wore only a sarung.

Sarung

I thought he was going to change into a proper hiking outfit. He did not.

He was very wholesome, by the way. Before we embarked on the hike, he expressed gratitude that we were all able to come together and celebrate this hike together. He encouraged us to sing along with him on the journey. Yeah... he carried a guitar and a drum for the hike. That is wild. I've only seen that in video games, not in real life!

Because of his bare outfit, I thought, “Oh, the terrain must be easy.” Well, it wasn't. There were screes. So many loose rocks and pebbles. He walked on them like it's nothing!

At the summit, we were greeted by a blanket of dense mist instead of a rewarding sunrise. At the top, I asked Kadek why he decided to hike barefoot. He had a good reason. He developed Tourette's Syndrome when he was 11. By chance, he discovered that his condition was hugely alleviated when he hiked up the mountain barefoot.

That's when it hit me. Well, that could make sense. Tourette's is a condition related to the nervous system. To the best of my understanding, reflexology works by stimulating the nerves.

Walking on stones

As always, that made me reflect on how much we take for granted today is beneficial to us. I wore shoes from when I was a little kid, and it became something normal. But is it really normal for humans to wear heavily padded footwear? What's the history of shoes? I know there's a barefoot running movement. I haven't quite wrapped my head around that topic, but I shall explore that.

Brb, I'm going to walk on some stones downstairs.


A snail on the sidewalk

A snail on the sidewalk

You're walking or running on the sidewalk.

You spotted a snail.

There, in the middle of the sidewalk.

Do you avoid and walk past it?

Or do you pick it up and move it aside so no one would accidentally run over it?

A plate of stir-fry long beans and a fork

A plate of stir-fry long beans and a fork

You're in a restaurant, eating with friends or family.

The waiter served a plate of long beans right in front of you.

A fork is provided with it.

Do you use the fork to try to grab as many long beans as you want?

Or do you ask the waiter if they have like a big spoon or something that will make it easier to scoop the long beans?

Company with broken processes

You just started a new job in a new company.

It's been 6 months.

You start noticing the ugly things — the gaps in processes, the toxic behavior of a teammate that goes unnoticed, the mess in the systems.

Do you look the other way, avoid the ugly things, and focus on what you like?

Or do you advocate for fixing the broken processes, calling out the toxic behavior, and fixing the systems?


I've noticed two types of response when dealing with an external situation:

  • influence; or
  • adapt

Sometimes, when things are out of our control, we have no choice but to adapt. We change our mindset and perspective.

At other times, we are given a choice: we can influence or adapt. Influencing is more difficult. You have to take action. It's more active. Adapting is more straightforward. It's passive. I'm not saying one is better than the other. I'm saying, be intentional with your choice of response.


I had a fascinating experience today. I was the event photographer at Ruth's casual wedding party. For the longest time, I've been mainly taking pictures of mostly still subjects (natural landscapes, buildings, etc.) in an outdoor setting where light is typically abundant. Today, I had to take photos of people in a completely different setting (moving subjects, indoors, with varying degrees of light). I have to admit that I was inexperienced. But I learned a few things. It was an excellent opportunity to hone my photography skills.


Lesson 1: on mind game

I'm an introvert. I don't mind approaching individual strangers. But, approaching a group of strangers talking amongst themselves? That was uncomfortable for me. It was out of my comfort zone. I was disappointed that I wasn't proactive enough to invite people to take group pics. Of course, it doesn't come naturally to me. But I could've done better. In retrospect, if I had changed my mindset, I would have been able to overcome that mental blocker. If only I keep in my mind: “today's an important event for Ruth, and I have one job — to capture and memorialize the space, time, and people at today's event.” If I can keep that in mind, it would've been easy to overcome my reluctance to approach groups of people. I would have been able to capture more attendees.


Lesson 2: on candid pics

Instead, I took pictures of people discreetly, thinking I would capture some candid shots. But candid pics are tricky, aren't they? In this particular event, there were a few obstacles to taking good candid pics: 1. We had a buffet. People often don't clear their empty plates after they finish eating. Empty plates don't look great in pictures. People who are eating also don't look great in pictures. Those are unglamorous. I would have been upset if I saw a photographer taking a picture of me eating. Yet, that's the exact mistake. 2. People sat in a circle, making it difficult to include everyone's faces in the pictures. It's not nice to take pictures of some faces and some backs. 3. I couldn't easily position myself discreetly in a good angle to take good candid pics. The space was quite packed, and if I moved to a particular angle, people would notice. Then, it won't be candid anymore.

In hindsight, it would have been nicer to just invite people to take group photos so they could prepare themselves and appear glamorous.


Lesson 3: on lenses

I'm using a Sony Alpha a6000 mirrorless camera. I bought two lenses today. One is a 35mm f/1.8 prime lens. The other is a 16-50mm f/3.5-5.6 lens. The reason I brought a prime lens is because I know it takes crisp pictures. It has a shallow depth of field. It might be great for an event. And it is for specific settings. The reason I brought the other lens was that the fixed focal length of the prime lens could pose a challenge when taking group photos. The field of view is not large, so it might be challenging to fit everyone into a pic.

During the event itself, the 16-50mm lens proved to be a better choice. Prime lenses are too static. To take good pics, one has to move around. And there isn't much luxury to be found in the area. A photographer has to be quick. Moments are fleeting. A prime lens also has a shallow depth of field. That becomes a problem when people stand in front of one another. Some people will get the focus, while others will be blurred. Good composition is challenging to achieve because it highly depends on the photographer's positioning since zooming in and out is not an option. Lastly, as mentioned, the fixed focal length makes it hard to fit many people in a picture.

A telephoto lens is probably the best because its long-ranging zoom helps with sub-ideal positioning rather than having to move here and there.


Lesson 4: on camera settings

Shutter speed has to be fast. People move. A slow shutter speed can create blurry pictures when there is motion. Fast shutter speed freezes actions.

One strange thing I noticed was the different apertures on the pictures I took. That's unusual because I had set my camera to aperture priority mode. I intentionally set my aperture to a low setting so that I could achieve a higher shutter speed. Should I have used shutter speed priority mode, though? To answer that, I need to do some experiments.

1/80 shutter speed isn't enough. A quick googling tells me that 1/100 to 1/200 should be fine.


I was disappointed with the pics I took. Nonetheless, it was a good learning experience. I've tried to learn photography multiple times in the past. However, the concepts don't stick as well when I don't practice them. As always, hands-on experience beats theory classes. Event photography is a different ballgame than landscape photography. I now have a higher appreciation for event photographers. They must be highly attuned to the environment in which they operate. They have to consider their positions, their subjects' positions, the lighting, the turn of events, and so on. They must constantly adjust to capture the best moments, allowing event owners to cherish those meaningful and memorable events forever.


A short but intense focus yields a better and quicker outcome than a long but mild focus.

It's common sense, but I gained a deeper understanding and appreciation when I deliberately reflected on it and experienced it. Friends in my circle who are smart and quick to get things done are also the most focused individuals I know. They may not necessarily know a concept or a new technology, but they learn quickly with their intense focus.

Cultivate intense focus because it enables you to accomplish more in a shorter amount of time. You'll do more and have a fuller life. You don't need to live a long life; you just need to live a focused life.

I was prompted to write this short piece when reading an excellent write-up on procrastination by Paul Graham here. Read it!