Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I just commented on the reddit post about this but I'll bring it in here too:

The app implementation is out of touch with modern Google Play privacy requirements and APIs.

I read through his code, starting with the Main Activity: https://github.com/M66B/FairEmail/blob/master/app/src/main/j...

1. He's using ancient APIs. All written in Java with Activities instead of Kotlin with a single Activity and many Fragments. There are some fragments but it's definitely an old writing style

2. He's using Tasks for multithreading/event handling

3. Using Handlers & runnables is a terrible idea and intrinsically fragile

4. The way he's handling synchro (persistent foreground service) is _explicitly something Google is targeting for battery issues_

5. This code is entirely unmaintainable. He's got a 3k line service file here: https://github.com/M66B/FairEmail/blob/maser/app/src/main/ja..., nested deeply with multiple different handlers running.

I'm not even going to discuss the fact that he has Logging statements peppered throughout the code etc.

This app looks like a 5+ year old code base, not something persistently maintained.

He also does not appear to use any modern Android APIs that Google requires, despite declaring the following restricted permissions:

1. READ_CONTACTS 2. READ_EXTERNAL_STORAGE

In fact I see him explicitly calling deprecated methods that Google has declared off limits: Line 474 of https://github.com/M66B/FairEmail/blob/master/app/src/main/j... `requestPermissions` is an illegal call, which he has documented as throwing an exception that he can't figure out.

That's absolutely a smoking gun and potentially the reason Google would ban him. ActivityResultLauncher is required for permissions grants.

My summary of this is: This is what bitrot looks like and what happens when you don't manage app scope to handle tech debt. It got too big to maintain.



Most of what you listed is either incorrect, irrelevant or purely subjective. I'm doubting your familiarity with the system.

> All written in Java with Activities instead of Kotlin

...

> The way he's handling synchro (persistent foreground service) is _explicitly something Google is targeting for battery issues_

Yes and Android will kill the app if it violates a constraint. It's not forbidden or won't get your app rejected.

> He also does not appear to use any modern Android APIs that Google requires, despite declaring the following restricted permissions

AAAAA. The use of those permissions is not forbidden, they're even needed for backwards compatibility. On newer Android versions and newer target API level, you probably have to start using the new APIs, but that's normal. This won't get even your app rejected. (Contacts is not special even in that aspect, you just have to have a good reason to use that)

> In fact I see him explicitly calling deprecated methods that Google has declared off limits

Deprecation doesn't mean absolutely forbidden. At worst it means that code won't work on newer Android versions and will throw an exception, won't get you rejected.

> That's absolutely a smoking gun and potentially the reason Google would ban him.

Absolutely none of those things is a sufficient reason for a ban. At worst a rejection might happen for other reasons stemming from legacy code, but I don't even that applies here.

Keeping up with the churn of Android takes work and is difficult for most, but legacy code won't get you a ban like this.

The reason is something else.


The ban is more explicitly stated in a different comment as having scraped & sent emails to a 3rd party server.

Also he targets API 32 so the app will crash if he's not using the right API.


Are we playing a game of telephone by adding extra "facts?"

"scraped and sent emails to a 3rd party server" is grossly exaggerating other comments which was also ended up being wrong in their assessment.


> He's using ancient APIs. All written in Java with Activities instead of Kotlin with a single Activity and many Fragments.

That doesn't mean it's ancient at all. Java isn't deprecated, and using Fragments instead of Activities is just one possible architectural approach.

I think Google recommends Kotlin now, but that's only been the case for a couple of years or so.

Google's constant demands for changes to how Android apps are configured are very annoying to the developer, but even they're not that bad.


A lot of my analysis is personal and subjective based on 5yoe as a full time Android Dev.

The ancient APIs is using Runnables/Handlers with Tasks more than it is using Java.

The single (or reduced) Activities with many fragments will improve stability.

Kotlin has been the official language of Android for a relatively short period of time, true, but it's entirely interoperable with all Java code, and improves maintainability _significantly_.

The main issue he's facing here is your last sentence: He refused to change how the app was configured. Use of illegal calls (which he helpfully posts the Stack Trace as a comment when it fails) means the app just doesn't work on modern Android without having to manually grant permissions.


> The main issue he's facing here is your last sentence: He refused to change how the app was configured.

I do have a lot of sympathy of for him. I also maintain an app which I provide for free to my users out of altruism.

I don't "refuse" to change how the app is configured, but I don't have time to constantly rewrite it.

Trying to keep up with the Google treadmill of required changes is extremely difficult for someone with a side project (I don't know if FairEmail is full time for its author). Example: I need to rewrite large portions of my app to use scoped storage, but even using the example code from the Google API docs already gets flagged as deprecated.

It might be tolerable if Android is your day job. I guess that's all Google cares about now - apps large enough to be profitable to give them a cut.

Personally I think Android as an O/S should not break userspace.


>Trying to keep up with the Google treadmill of required changes is extremely difficult for someone with a side project (I don't know if FairEmail is full time for its author). Example: I need to rewrite large portions of my app to use scoped storage, but even using the example code from the Google API docs already gets flagged as deprecated.

I mean, I sympathize, but that's sort of the agreement you make if you want to be in the Play Store, right? Like, if you don't have time to maintain your app, that's totally OK -- but at least you have other methods of distributing your app if you want. But if you want to use Google's distribution platform, following their rules for what is and isn't allowed seems fair.


> following their rules for what is and isn't allowed seems fair

It depends on how you look at it. That is literally the deal, yes, but it's a poor deal for developers of free apps.

We make Android's platform more valuable, for free, and in return we have to constantly rewrite our apps because of poorly-thought out policies that keep changing.

The suspicion is that many of these changes are unnecessary and a result of Google's notorious "promotion-driven development".

I think the most annoying aspect of it is that Android changes so often and so fast that they can't even keep their own documentation in sync.


And scoped storage is basically a nuclear bomb. Nvidia is still struggling with it on the Shield/Android TV as it has completely upset the turnip cart in regards to things like Plex Media Server that worked just fine before scoped storage.

Google doesn't care. Change for the sake of change is the name of the game, so apps that aren't maintained professionally are screwed


>Kotlin has been the official language of Android for a relatively short period of time, true, but it's entirely interoperable with all Java code, and improves maintainability _significantly_.

Has the JavaScript culture of rewriting everything every two years purely for the sake of change infected android now too?


Yes, we all exist on treadmills and race the Red Queen nowadays.


It's been that way since at least Android 9


Thank goodness Google is looking out for my privacy!

It's doing about as good of a job at that as it is in upholding my right to decide what apps to run on my device.

It's remarkable that all that so-called "unmaintainable code" results in an app which is far more powerful, and just as reliable, as Gmail.


I dread to think what gmail's codebase looks like, I've heard Stories. Some resources:

https://www.quora.com/What-was-the-code-quality-of-the-initi...

https://news.ycombinator.com/item?id=2452126


1. The issue here is one of failing to maintain the code, so I don't see how calling it unmaintainable is unfair

2. Google is absolutely doing a lot to prevent 3rd parties from reading your contacts and sending them to a 3rd party server (like this developer was doing). I'm not saying your data is private, I'm saying you have more control over data privacy... but probably not from Google.

3. You can still run this app on your device. Android Studio is free. Go fork, build & side-load it. It will however crash on later versions of Android. Manually giving it permissions should resolve that through at least Android 13. We'll see what 14 brings.


1. How is he failing to maintain it? There was no single issue with code quality in this situation.

2. He is not sending contact list anywhere. If application finds john@gmail.com in your contact list, it makes request for https://gmail.com/favicon.ico it's off by default, and has disclaimer next to it. It poses literally zero privacy risk.

3. I use this app daily on Android 12, and this is last android version available for regular users. There's zero issues with it. I would be very happy if all apps were maintained up to this level. I couldn't care less about java being used in order to make that happen.


> You can still run this app on your device.

For now. Google's in the process of killing the ability to sideload apks


One thing I've noticed about FairEmail is that it is able to do low power push messages via IMAP IDLE, without any kind of external cloud push platform, and maintain this reliably across connectivity state changes.

Indeed, with a good mail server, it often seems more reliable than Gmail and their own push implementation.

I don't know enough about the design patterns expected of an android app, but I think there's something to be said for getting robust functionality on as many versions of android as possible (including older devices), and in then keeping that sync engine stable once it works. Given the amount of per device bugs you encounter, moving to newer APIs is likely to result in a whole host of new regression issues that users won't like.


> it often seems more reliable than Gmail and their own push implementation.

Definitely is. Gmail doesn't set priority on email, so it gets stuck behind Doze, particularly on devices with more aggressive power management features(Samsung, OnePlus, etc). FairEmail is the most reliable email client I've found on the platform


I'm not an android dev, can someone weigh in here? Why is using Tasks bad? Who really cares if he uses a design pattern from five years ago? I'm sure my website code is at least twice as old and PHP, should I spend time rewriting that in Kotlin, too?

> The way he's handling synchro (persistent foreground service) is _explicitly something Google is targeting for battery issues_

My phone has a terrible battery that will drain in 3 hours while navigating¹, but FairEmail running in the background is not noticeable. I've used K9 before as well and didn't notice any difference in battery use.

¹ worst battery I ever had in a phone, and also the most expensive phone I ever had... thankfully I got it second-hand and didn't pay the full price for this. Got a second one for my mom which was equally bad, so we had her device's battery replaced by samsung for iirc €110, but her battery longevity barely improved. Coincidentally I ruled out an hour ago that it's the screen that causes the drain, my next best guess is the CPU. Not sure why this model is such a battery hog, but anyway FairEmail doesn't impact it.

> This app looks like a 5+ year old code base, not something persistently maintained.

FairEmail was the only app that would receive updates every time the f-droid repository had a new release. Most apps go months between updates but of FairMail there were updates almost daily. And it's just this guy working on it all the time, I don't know where he got the energy. So maybe not the "maintenance" shiny new code patterns you'd like to see, but the maintenance I was very happy about was a constant stream of updates.


The comments on code quality are somewhat fair, and there are better ways of doing things, but calling it "out of touch" because it's not been rewritten in kotlin is frankly silly.

Additionally, None of this is justification for removal from the store, the comment calling `requestPermissions` illegal is unjust, there's nothing incorrect about its use here (notwithstanding Play Store policies around contacts). ActivityResultLauncher is a more modern (imo superior) and recommended, but it is not a requirement.

God forbid we have some tolerance for developers who don't want to spend every waking moment rewriting their app to use whatever new API Google have just added...


It's illegal because it crashes the app on the latest versions of Android. It's an illegal operation, not "against the law in N countries" type of illegal, more the "Divide by 0" type of illegal.

The out of touch is my personal assessment of reading through the code: They doesn't seem to recognize the benefits of the modern Android code styles which would reduce their workload, decrease the boilerplate they're writing, and increase the stability of the app overall.


So how much time would a rewrite take him you think?


I was just documenting issues I saw with the code from a maintainability standpoint.

The older Tasks & Runnable API is very fragile when it comes to lifecycle changes and will cause crashes regularly. This means that you end up building up a ton of patchy code over time to try and do what Kotlin's lifecycle aware coroutines will do for you.

So of course he spent all his time patching: His code was fragile to begin with. You don't end up so many 3kLOC files without poor architecture.

Look: I've been there. Ripping down fragile monoliths to refactor seems like a waste of time because you'll spend 3 months rewriting code while bugs pile up. It's worth doing though because you'll save 6 months of bug fixes in the future.

When it comes to the APIs there's another comment here that explains explicitly the spyware issue (He was scraping emails and sending them to a 3rd party), but for the Android APIs that he was abusing they're recent privacy focused changes that cannot be ignored.

Sure your website will run fine but fundamentally HTML is very similar to what it was a decade ago. Android's runtime is constantly evolving as the phones change to new demands. Battery usage is something they're exerting more control over, and I personally find that annoying. Privacy is another thing: I'm all for that. The permissions requests he was doing will literally crash the app for modern Android. You cannot request permissions that way anymore because the API has changed to make it more explicit.

It sucks that he didn't care enough to fix it, but here we are. He's done an admirable job limping along the mess of a code base but he hasn't implemented the fixes that were needed for it to work on modern phones.


Works great on Pixel 6. Used very heavily every day. May you share your definition of "modern phone"?


> of course he spent all his time patching

More like adding features if you look at the changelogs for the near-daily releases


> Who really cares if he uses a design pattern from five years ago?

Nobody, definitely not Google Play.


Having a bunch of legacy code isn’t really a valid reason to block an app from being on the Play Store. Your code review isn’t particularly useful here. It might be if you went “oh this permissions API is not supposed to be used and you can see Google asked the app to use the new API to be approved” but that’s not what seems to have happened here?


Thanks for actually taking a look.

I can imagine that the developer would have been more willing to make changes if Google had sent him the list you have compiled here.


I call bullshit on this. Google should not get to decide this. As I consumer I want this app.


Then build & side load it.

The issue is that he's not respecting the required APIs. It literally does not function on a modern Android device because of the permissions.

Do you want privacy on your phone? Apps are required to implement the new API for better user control of privacy and permissions.

The developer was incapable of maintaining their app to modern API changes. That sucks but it's like complaining that you can't run a Windows 95 program on Win 7 without having to do some work on it yourself.


> It literally does not function on a modern Android device because of the permissions.

It literally does. I'm using it on Android 12. Far from "not functioning", it has the most reliable IMAP IDLE support of any Android app that I've tried.


> it has the most reliable IMAP IDLE support of any Android app that I've tried.

Sad that this has to be stated in 2022. Android is the only platform I have this problem with


The stuff about APIs is nonsense. The app works fine. It's better and more secure that Google's own email client.

The problem is Google has no place making these decisions. This is textbook anticompetitive behaviour. The developer is based in EU so I hope (and expect) that google gets a hefty fine.

And yes, I will be sideloading it.


I'm sad to see it go as well. It's my main mail client on Android.

The GP on this thread is completely ridiculous. "You're not using Kotlin and instead use Java" is the most ridiculous thing on such an issue I've ever seen. Email clients battery usage is a really hard to get right. Especially since Fairmail gives you so many options on the synching behavior. So much so that a lot of iOS email clients actually store mail credentials on a third party server and sync your emails there to send push notifications. That's an absolutely security nightmare and yet that's somehow ok.

Really sucks to have it pulled and even more disturbing to see people here justify it. I can't help but wonder if the person above is a google employee.


Java vs Kotlin is a maintainability issue.

The reason it's pulled isn't java vs kot: It's refusing to use the modern APIs that are required for it to function on Android 11+.

My outline specifically mentions the use of illegal calls which will literally just crash on later android versions. He even has his call stack pasted as a comment.


> The reason it's pulled isn't java vs kot: It's refusing to use the modern APIs that are required for it to function on Android 11+.

That's not a reason to pull an app. It's a reason to tell users of Android 11+ that the app isn't compatible with their device, but everyone else should still be able to install it.


Great.

When you update to Android 11 or 12 it will cease to work well, because it will crash when requesting a permission. You can get around it by manually adding permissions.

When you encounter those issues I suggest forking it and doing the work he refuses to: Use ActivityResultLauncher with registerForActivityResult to request permissions.


> It's better and more secure that Google's own email client.

Have you or someone else audited the code or what is this based on?


> Do you want privacy on your phone?

lol. There is no privacy on your phone if you have Google's spyware on it. So your point is complete bullshit.


> All written in Java with Activities instead of Kotlin

> The app implementation is out of touch with modern Google Play privacy requirements and APIs.

Kotlin is never required. I think you might be the one of touch.


I don't see what is wrong with an app being 5 years old.

That's not very old in the scale of things!


> 1. He's using ancient APIs

Maybe I don't fully grok how APIs are evaluated here, but FairEmail seems to be on API 32 (Android 12L), which is the very latest




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: