Why not just assign a random 64-bit number to send with the user's id. Take the 64-bit number, break it into 5-bit chunks, and use each 5-bit chunk to index into a 32-character alphabet: 23456789ABCDEFGHJKLMNPQRSTUVWXYZ (conveniently omitting 01IO). With a 64-bit number and 5-bits/code (except the last one) you get a 13 character slug to use to identify the user. You could pad it with 2 random characters to give 3 groups of 5 characters if you wanted.
Make the id and the slug part of the login url. Check the value of the slug stored with the id in the database to make sure they are the same. I think for most purposes this would be a large enough value to make it extremely hard to guess -- the number is random after all -- which slug goes with which user id. Using a cryptographically strong random number generator, I would think it would be highly unlikely that you'd even get repeat numbers for any of your users.
It might look like:
http://example.com/activate?userid=bgates&validate=GY45M-RHQBN-32GYM
Using a hash of known values might actually make it easier for someone to guess the correct code than using a random number. Using a hash one only has to guess which bits you're using and run them through various hash algorithms. If someone is able to piece these together, say given a few examples and enough time to try various combinations, then all they have to do to crack someone's code is determine the (probably) commonly known attributes for a given person and use those to impersonate them and create an account. With a strong random number assigned to each individual they're only left with a brute force attack.