For the last 10 years, I’ve used zx2c4.com for my e-mail, and have had it forwarded to whichever provider I was using, which most recently happens to be gmail. Ten years ago, it seemed like a good idea to have “catch-all” e-mail, whereby anything you put at zx2c4.com would be sent to me. This was great for a while, and on every site I would visit that required an e-mail, I’d give them a new one. JasonHatesWhenNikeDotComSpamsHim [at] zx2c4.com I would use for nike.com, and then I’d know for certain if they ever sold my e-mail address. For more serious sites, I would just use their site name or something easy to remember about their site. For personal communications, all my friends knew this quality of zx2c4.com, and would send things to anything they wanted — YouAreAGoofBall [at] zx2c4.com, for example.

This was all fun and games and helped filter out some spam throughout the years, but it seems like it’s time I settle down on one e-mail address. I would also like to find a different domain than zx2c4.com for personal communications that’s much easier to remember (any suggestions?). The problem is – it’s very difficult to switch away from catch-all e-mail. My initial idea was to gather up all the e-mails of individuals who have sent e-mail to something other than my main e-mail address, and automate the process with a form letter sent via SMTP that says something like “Dear joe@shmoe.com, You have sent letters to asdfasf [at] zx2c4.com, thatthang [at] zx2c4.com, jojomojito [at] zx2c4.com. Please note that starting May 1, 2010, only whatIDecide [at] zx2c4.com will be valid. Thank you, Jason”. And then painstakingly go to all of the websites with logins and change my e-mail address for every.single.solitary.one one.by.one. At first this all seemed doable.

But then I started investigating…. Since I started using GMail in March of 2005, I have received e-mail from 1,299 different e-mail addresses on 267 different zx2c4.com e-mail addresses, not to mention lost e-mail from the 5 years prior. I built this python script to give me a good layout of what’s up:

#!/usr/bin/env python
# -*- coding: iso-8859-1 -*-
from imaplib import IMAP4_SSL
from optparse import OptionParser
from email.parser import HeaderParser
from email.message import Message
from email.utils import getaddresses
import sys
import os.path
import os
 
def main():
	parser = OptionParser(usage="%prog --username/-u USERNAME --password/-p PASSWORD --mode/-m MODE [--domain/-d DOMAIN] [--cachedir/-c CACHEDIR]", description="Downloads gmail message headers and determines the set of all e-mail addresses on DOMAIN at which people have emailed you.")
	parser.add_option("-u", "--username", action="store", type="string", metavar="USERNAME", help="Gmail username")
	parser.add_option("-p", "--password", action="store", type="string", metavar="PASSWORD", help="Gmail password")
	parser.add_option("-d", "--domain", action="store", type="string", metavar="DOMAIN", help="Domain name")
	parser.add_option("-c", "--cachedir", action="store", type="string", metavar="CACHEDIR", help="The directory to cache fetched headers for subsequent runs")
	parser.add_option("-m", "--mode", action="store", type="string", metavar="SENDERSFILE", help="If the mode is \"to\", this prints a list of all the emails you've received email on. If the mode is \"from\" this prints a list of everyone who has sent you email. If the mode is \"frombyto\" this prints a list of all the addresses that have emailed you sorted by the address at which you received email. If the mode is \"tobyfrom\" this prints a of all the addresses you have received e-mail from sorted and duplicated by who sent the e-mail.")
	(options, args) = parser.parse_args()
	if options.username == None or options.password == None:
		parser.error("Username and password are all required.")
	if options.mode != "from" and options.mode != "to" and options.mode != "frombyto" and options.mode != "tobyfrom":
		parser.error("You must specify a mode.")
	if not options.username.lower().endswith("@gmail.com") and not options.username.lower().endswith("@googlemail.com"):
		options.username += "@gmail.com"
	if options.cachedir != None and not os.path.exists(options.cachedir):
		try:
			os.makedirs(options.cachedir)
		except:
			sys.stderr.write("Could not make cache dir. Skipping cache.\n")
			options.cachedir = None
 
	imap = IMAP4_SSL("imap.gmail.com")
	imap.login(options.username, options.password)
	imap.select("[Gmail]/All Mail", True)
	typ, data = imap.search(None, 'ALL')
	if typ != "OK":
		sys.exit(("Could not search properly: %s" % typ))
	emailAddresses = {}
	data = data[0].split()
	length = len(data)
	counter = 0
	parser = HeaderParser()
	for num in data:
		counter += 1
		if options.cachedir != None:
			cachePath = os.path.join(options.cachedir, num)
		else:
			cachePath = None
		if cachePath != None and os.path.exists(cachePath):
			message = parser.parse(open(cachePath, "r"))
		else:
			try:
				typ, data = imap.fetch(num, '(RFC822.HEADER)')
			except:
				sys.stderr.write("Failed to fetch ID %s\n" % num)
				continue
			if typ != "OK":
				sys.stderr.write("Failed to fetch ID %s: %s\n" % (num, typ))
				continue
			if cachePath != None:
				try:
					f = open(cachePath, "w")
					f.write(data[0][1])
					f.close()
				except:
					sys.stderr.write("Could not write cache for %s" % num)
			message = parser.parsestr(data[0][1], True)
		tos = message.get_all('to', [])
		ccs = message.get_all('cc', [])
		resent_tos = message.get_all('resent-to', [])
		resent_ccs = message.get_all('resent-cc', [])
		all_recipients = getaddresses(tos + ccs + resent_tos + resent_ccs)
		for address in all_recipients:
			if len(address) == 2 and (options.domain == None or address[1].endswith(options.domain)):
				to = address[1].lower()
				fros = getaddresses(message.get_all('from', []))
				fro_addresses = set()
				for addr in fros:
					if len(addr) == 2:
						fro_addresses.add(addr[1].lower())
				if options.mode == "to" or options.mode == "tobyfrom":
					if to not in emailAddresses:
						emailAddresses[to] = set()
					emailAddresses[to] = emailAddresses[to].union(fro_addresses)
				elif options.mode == "from" or options.mode == "frombyto":
					for fro in fro_addresses:
						if fro not in emailAddresses:
							emailAddresses[fro] = set()
						emailAddresses[fro].add(to)
				sys.stderr.write("[%s of %s]: Message to %s from %s.\n" % (counter, length, address[1], fro_addresses))
		if len(all_recipients) == 0:
			sys.stderr.write("[%s of %s]: Message has empty To header.\n" % (counter, length))
	imap.close()
	imap.logout()
	if options.mode == "to" or options.mode == "from":
		for addr in emailAddresses.keys():
			print addr
	elif options.mode == "tobyfrom" or options.mode == "frombyto":
		for to, fro in emailAddresses.items():
			print to
			for f in fro:
				print "\t%s" % f
 
if __name__ == '__main__':
	main()

The situation seems daunting. That is so many email addresses, so many senders, so many website logins to change, so many people who have to update their address books. So what do I do? What will I do? How important is it to switch away from catch-all? I might just be locked in for life.

March 4, 2010 · [Print]

12 Comments to “Trying to Leave Catch-All E-Mail Behind”

  1. Josh BA says:

    Here’s what I would do:

    1)From now on, only give the single address you want to keep to new people and sites.

    2)Send notifications to the actual people about the address change. (this is probably the most tedious part)

    3)Change the e-mail address at the sites you care about getting more mail from or need the login for. “Need” meaning that signing up a new account if you find out you need to use the service would result is lesser service than keeping that account (something like slashdot or ebay which keeps track of reputation or which you build one like a forum). Otherwise, just create a new account when you find need to with your new address.

    4)Set it so that your “from” e-mail address is always the new single one, even when replying to messages sent to a different address. This will make it easier to keep threads going as then no-one will need to manually fix the “reply to” field.

    5)Every time you get a message to an address you want to get rid of (any other than your new consolidated one) from an actual person, remind the person to use the new address.

    It means keeping the catch-all for a while longer, but eventually the only things being sent to your non consolidated address will be things you don’t care about and the work will be, for the most part, spread out so you don’t have to both do everything at once, and expect others to fix their behavior immediately.

    • Thanks a lot for your suggestions, Josh. Actually number 2 should be the easiest, because using the data from that python script I can more or less automate the process. It’ll just be a matter of filtering out the non-human email recipients, which will take some work for sure. What I’m most worried about is number number 3. I hate to have stale accounts.

  2. Ryan says:

    First, fix your From: headers so that replies always go to the correct address.

    Since you’re forwarding all this stuff to Gmail, create a filter that catches all mail sent to yourdomain.com but NOT to your_real_address@yourdomain.com. Set that filter to apply a “Catchall” label. Apply that filter to all previous messasges as well. Then at the very least you can simplify your python script to only consider this one label.

    In the future, every time a new mail gets the Catchall label, handle it as you please. Keep an eye on the label and eventually, the catchall emails should dwindle to nothing, at which point you can disable your catchall and delete the label and filter from Gmail.

  3. Chris says:

    You can do custom NDR mails, so if someone gets a 550 (no such user) when trying to mail you, your personalized NDR message says “This address is no good, use this other one instead”. Make it look as little like a standard bounce as possible, and as much like a personal note as you can.

    Anyone who’s an actual person that really wants to mail you should get the message, and any spambots won’t care one way or the other, so you’re not really exposing yourself to more spam harvesting.

    Since you’ve had your current domain for a while, you probably get a respectable amount of spam daily to begin with, so I should think you already have a method of dealing with it. As a side note, I’d probably just leave the per-site addresses alone, especially if there are too many to remember. It makes it super easy to filter for spam to those addresses (if recipient = nike@domain.com and sender does not contain nike.com, delete it), I really sort of wish I’d been doing that myself all these years.

  4. Dotan Cohen says:

    I also use a catchall email address in the same fashion that you mention. This Thunderbird extension makes it easy:
    https://addons.mozilla.org/en-US/thunderbird/addon/594

    There are two open Kmail bugs for making this possible in Kmail:
    https://bugs.kde.org/show_bug.cgi?id=72926
    https://bugs.kde.org/show_bug.cgi?id=159251

    You might want to vote for those bugs.

  5. Lou Johnson says:

    I read your blog frequently and I just thought I’d say keep up the good work!

  6. wow!cool thanks for sharing! :) thank you very much!

  7. koi fish says:

    One of the magnificent features about blogs is the facility to authorize all of us to share our thoughts on the World Wide Web. Sometimes it’s just awesome to blast away your thoughts and get it out of your mind. And you want to know what is brilliant about it? It doesn’t matter what the subject are! There will always be an interested person to read your ideas. Thoughts by koi fish. Thank you for sharing yours.

  8. Parier Rugby says:

    Merci, article fort interressant.

  9. whois says:

    oh my, will give this a try, thank’s for sharing this article. cheers!=)

  10. Recette cake says:

    Thx for this article.

  11. David says:

    Josh,

    The following my be helpful.

    I actually went through switching over about a year ago. I thought about it for a few
    years and then made the change. I wanted a shorter email and the first domain I had and
    a handful of accounts I tried to sign up for would not recognize the .info extention
    as valid. In addition the first first domain I use was actually quite long.

    For your question on what would be a good new domain, you may want to try a
    domain search form to find a domain name with your initials
    or some other letter combination that makes sense to you. For example I used one to
    find a domain with my two initials seperated by the letter n and a number at the end.
    This shorter domain is much easier to type in all the time than the other one I used.

    After I decided to make the switch I didn’t just switch right away.
    It actually took me about a year and half. After creating the second account
    and changing all the accounts over that I kept track of I ran both catch all
    emails for about a year and a half. This way I made sure I didn’t miss anything.

    Hope that helps. Stay safe.

    David
    $.02

Leave a Reply