Unknown salt
I have a bunch of MD5 hashes created with an algorithm md5(md5($pass).$salt) where $salt is an unknown 3-character string (different for each hash.)

It seems that there's a semi-undocumented mode -m 2611 that handles this algorithm, but it requires the salt to be in the input file. I only have straight hashes in the file, and hashcat refuses to load them due to "Line-length exceptions", no matter what I try.

Is there any way to search through all possible salts?
Create all possible variants using maskprocessor plus a leading ":" to file A, then use combinator.bin from hashcat-utils with your current hashlist and file A to merge them to create a large hashlist, then feed hashcat with that list with mode 2611. Note that this will slow down the attack by 95^3.
That would only work for a small number of hashes. Otherwise it'll slow down the attack a lot more than 95^3 (which is why I was hoping for an automated in-memory solution.)
Let's say I have a 100M wordlist. Normally I get 2B hashes/sec MD5 (GeForce 980), two MD5 calls per hash here, so, 1B hashes/sec, times 95^3 (call it 100^3 = 1M), 1000 words/s, and I should be done in a day for any reasonable number of hashes.

Now, if I have 10M hashes, it means I have to write 10M * 95^3 = 10 trillion lines (so, 400 terabytes). Since hashcat can't eat a 400 terabyte hashlist, I'm going to feed it in chunks of 100M, so I'll have to launch it 100,000 times.
I just did a test with 10M hashes x 10 salts (100M lines total) and it took hashcat (3.5.0) 12 minutes start to finish (including 8 minutes just to load and sort the hashlist), which gives me projected time 2 years for all salts.
It's your own fault if you do not export the salt, which is freely available in the database. If you intentionally make your life harder than necessary, that's what you get.
what's happened to the -e option?
The -e option was in hashcat legacy only