How to speed up query with anti-joins
Your best bet is probably to solve this at the application level.  This looks like a query you run as part of a data-cleaning exercise.  If that is so, why do you care if it takes 6 seconds to run, and why do you restrict it to 100 rows rather than reading all of them in one shot?  Perhaps you could use a materialized view or some other caching mechanism.  If you reject that option, read on for some "second best" options.


  I should also mention that the users_email_subscribers_idx is showing an Index Scan and not Index Only Scan likely because the index is being updated regularly.


That isn't why. You need columns out of the Users table that are not contained in the index, such as firstName and id. If you created an index with all those column at the end of the column list, you would get an index only scan. That might make the query 20% faster, but isn't going to make it 99% faster.


               Heap Fetches: 1153034



You need to vacuum UserEmails more aggressively.  Again, it won't be a 99% improvement, but it should help some.  Autovacuum doesn't do a good job at keeping tables sufficiently vacuumed to optimize index-only scans.  You can do manual vacuums.  Or you can try to force autovacuum to do a better job by lowering the per-table setting of "autovacuum_vacuum_scale_factor" to zero, and then setting the per table "autovacuum_vacuum_threshold" to be in control of the vacuuming.  If the table is updated randomly throughout the table, I'd set "autovacuum_vacuum_threshold" to about 1/20 of the number of blocks in the table.

How does the query perform if you experimentally set enable_nestedloop to off?  This will probably give you hash anti joins, and if your version is new enough you might get parallel versions of them.