Improvised Standing Desk
Failing Fast with FastMail.fm
So I thought I’d try a non-free email provider for a new domain I’m working on. I’ve used both complimentary email accounts for domains I’ve registered at places like GoDaddy, as well as free accounts at places like Yahoo and Google. I thought it would be interesting, for a change, to use a provider whose primary focus was email.
It was was actually kind of difficult to find anybody still providing email as a their primary business. I suppose it is hard to compete with free. After some research, I settled on FastMail.fm and created an account on August 29th, 2011.
I can summarize my experience to date with three words:
Worst. Service. Ever.
Signing up was easy enough, and a quick test email later confirmed everything was working. I logged onto my web hosting provider and began forwarding email for my new domain to my new FastMail account. I didn’t even have a web site up yet, so I didn’t expect much traffic.
Things went down hill from there.
I came back a few days later to add my account to Outlook, and I noticed several bounced messages in my inbox. Some looked like they’d been sent from my account, but I hadn’t sent them. I also noticed a lot of what looked like spam. I chalked this up to the fact that FastMail has been around a while, and from their blog, it didn’t seem like the strongest spam protection was enabled by default.
The bounced messages were disturbing. I hadn’t sent them, and they were clearly spam, but I’d chosen a strong random password for my account (117 bits, according to KeePass). I’d only ever accessed the account from home, not some unprotected wireless network at the local coffee shop, so I didn’t think my account had been hacked. I deleted the junk messages, configured Outlook, and logged out. I’d check back in a while to see if the spam persisted.
Nine days later, I started Outlook and went to check my messages to see if the amount of spam I was getting had changed. Outlook complained that my username or password for my FastMail account was incorrect. I double checked them, then tried again. No dice. I opened up a browser and tried to log into my FastMail account and was greeted with this message:
The account you are trying to access has been disabled due to over-quota use, or usage abuse. The system limits the number and size of emails you can send in an hour as described here and here. You will have been sent a warning email to your account, and your backup address when you reached half your usage quota, and again when you reached your full limit. These emails will describe the limit you reached, and why your account was disabled.
I scratched my head for a minute trying to think how this might have happened. Had my account filled up with junk because I was routing all email traffic for my new domain to it? I reconfigured email forwarding on my domain to bounce everything but one specific address, then logged into FastMail’s support page and left the following message on September 8th:
I tried to log into my account, and it said I was over-quota and that an email had been sent to my contact address, but I never received it. I haven’t sent out any emails on this account, so I’m confused why I’m getting an over quota problem.
I’ve attached the only email I’ve ever received from fastmail.
I attached my order confirmation email, the only email I’d ever received from FastMail. The next day, I received this unhelpful response from a FastMail admin by the name of Vinodh Khumar:
Hi,
Your FastMail account was recently detected sending bulk/duplicative emails. The Terms of Service that you agreed to on signup prohibits sending of “duplicative messages”.
—
http://www.fastmail.fm/docs/terms.htm
Section 4
…
By way of example, and not as a limitation, you agree not to: Use the Service in connection with … any duplicative or unsolicited messages
—Consequently your account sending has been locked.
If you can ensure that you would not use your account for further bulk mails, we’ll be happy to unlock your account. If not, we suggest you look for another provider.
There are a number of other providers out there that provide much better ways for sending bulk emails.
I recommend you check out:
—
*** Newsletter sending servicesHelps you send newsletters and other regular correspondence to people on
a mailing list you have. Helps you build the newsletter with templates,
gain analytical insight (eg who reads the newsletter, who clicks on
links in the newsletter, etc), and maintain the mailing list (eg find
dead bouncing addresses, handle unsubscribe requests, etc).http://www.mailchimp.com/
http://www.campaignmonitor.com/
http://www.aweber.com/
*** SMTP/API/notification sending services
Helps you send emails like notifications or other custom emails. Provide
multiple integration APIs and monitoring services.http://aws.amazon.com/ses/
http://postmarkapp.com/
http://www.socketlabs.com/
http://sendgrid.com/
———–
They will allow you to manage your subscriptions and email sending much better than Fastmail can. Hope you understand.
FM Webmaster
This was not really the answer I was looking for. I tried to explain that I had not sent these messages.
I understand your terms of service, but I’m confused how my account is sending any emails at all. I only just created it and I don’t think I’ve ever sent anything from this account. I’ve only sent a couple of emails to this account, one directly and one via email forwarding I’ve configured for a new domain.
I did notice lots of bounced mail warnings and other spam when last I logged in, but I thought that was because fastmail.fm had been around awhile and got lots of spam directed to it.
To reiterate, I have *not* been sending bulk email from this account. Perhaps my account was hacked, I don’t know. All I know I that I have not been sending bulk emails from this account.
Can my account be purged and my password reset so that I can regain access to it?
Its been 3 days now. I’m still locked out of my account, and I’ve yet to I receive a reply to the previous message. My money’s gone, and frankly, I’m a little worried they have my credit card on file.
In any event, I guess I’ll be sticking with Gmail.
Update 2011-09-12
After nearly 4 days of waiting for a response to my reply above, my support ticket was unceremoniously closed without comment from Vinodh or anyone else at FastMail. I’ve opened a new ticket. At this point, I just want my money back.
Enforce Strong Django Passwords
We’re using Django 1.3 for a new project at work. One of the things Django provides us with out of the box are convenient password change/reset forms and views. However, they don’t enforce any kind of password strength. As the application touches on financial data, it was suggested we nudge our users towards stronger passwords.
A quick search found django-passwords by Donald Stufft. The source code can be found here.
The django-passwords application provides a PasswordField and validators for enforcing stronger passwords with a number of options. I’ll show you what I did to integrate it with Django’s built-in password change and reset views.
First, install django-passwords with with pip or easy_install. Next, edit your settings.py file and add the application and your preferred password strength settings.
INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.sites',
'django.contrib.messages',
'django.contrib.staticfiles',
# Uncomment the next line to enable the admin:
'django.contrib.admin',
# Uncomment the next line to enable admin documentation:
# 'django.contrib.admindocs',
'passwords',
)
# Minimum password strength settings. See the GitHub page for defaults.
# https://github.com/dstufft/django-passwords/
PASSWORD_MIN_LENGTH = 8
PASSWORD_COMPLEXITY = { "UPPER": 1, "LOWER": 1, "DIGITS": 1 }
In the example above, I’ve configured settings.py file to require passwords that are at least 8 characters long and contain at least one uppercase, one lowercase, and one numeric character. Now, any place I use a PasswordField, text entered will be validated against these requirements.
If you wish to use Django’s included password reset/change views, you have one more step do. You’ll need to extend django.contrib.auth.forms.SetPasswordForm and django.contrib.auth.forms.PasswordChangeForm and add the validate_length, complexity, dictionary_words, and common_sequences validators to those forms’ new_password1 CharFields.
EDIT: Matt Austin was kind enough to point out that all your really need to do is override one of the password fields in SetPasswordForm and PasswordChangeForm with PasswordField, so I’ve replaced my convoluted brain-dead implementation with his suggestion below.
from django.contrib.auth.forms import SetPasswordForm, PasswordChangeForm
from django.utils.translation import ugettext_lazy as _
from passwords.fields import PasswordField
class ValidatingSetPasswordForm(SetPasswordForm):
new_password2 = PasswordField(label=_("New password confirmation"))
class ValidatingPasswordChangeForm(PasswordChangeForm):
new_password2 = PasswordField(label=_("New password confirmation"))
I put mine in a forms.py file in my application package. Finally, you need to replace the default forms with the new validating versions in the password routes of your urls.py file.
url(r'^password_change/$', 'django.contrib.auth.views.password_change',
{'password_change_form': TimeStampedPasswordChangeForm}),
url(r'^password_changed/$', 'django.contrib.auth.views.password_change_done'),
url(r'^password_reset/$', 'django.contrib.auth.views.password_reset'),
url(r'^password_reset_done/$', 'django.contrib.auth.views.password_reset_done'),
url(r'^password_reset_complete/$', 'django.contrib.auth.views.password_reset_complete'),
url(r'^password_reset_confirm/(?P<uidb36>[-\w]+)/(?P<token>[-\w]+)/$',
'django.contrib.auth.views.password_reset_confirm',
{'set_password_form': TimeStampedSetPasswordForm}),
Congratulations, your site should now be enforcing the heck out of user passwords. However, let’s not get too full of ourselves. XKCD explains why this probably isn’t solving the real problem of password security anyway.
Multiple Python Versions on OSX with Virtualenv and Homebrew
Since writing my post on configuring multiple versions of Python on OSX with Virtualenv and Macports, I’ve switched from Macports to Homebrew as my package manager for Unix utilities on OSX. I did this for a couple of reasons. Homebrew seems to install less dependencies than Macports or Fink. Also, most of my Python development has settled on Python 2.7 and occasionally Python 3 for tasks that don’t require external libraries that only run on Python 2.x. So for me, an easier install with less gunk on my hard drive is a fair trade for losing the latest updates to Python 2.4, 2.5, and 2.6. In this post, I’ll describe my setup.
The first thing I did was uninstall Macports. Homebrew has fairly up-to-date versions all of the Unix packages I use on a daily basis, including git, subversion, bash_completion, Python, Qt, PyQt, and their supporting libraries. As such, I don’t need Macports taking up additional hard drive space and potentially causing conflicts with Homebrew’s packages.
Next, I installed (or update) pip, virtualenv, and virtualenvwrapper in my Mac’s default Python (2.6.1 on Snow Leopard) via easy_install (or pip itself). These are usually the only 3rd-party Python packages I install in the system Python’s site-packages folder.
The next step is to brew install the packages I mentioned above. If you’re looking for a Unix port other than those I use, check out the formula folder on Github for the current list of packages supported by Homebrew. You can also use brew search to get a list at the Terminal (fwiw, I use iTerm).
Next, I remove the Macports configuration from my bash ~/.profile and replace it with the following:
# virtualenvwrapper
export WORKON_HOME=$HOME/VirtualEnvs
if [ -f /usr/local/bin/virtualenvwrapper.sh ]; then
source /usr/local/bin/virtualenvwrapper.sh
fi
# bash completion
if [ -f `brew --prefix`/etc/bash_completion ]; then
. `brew --prefix`/etc/bash_completion
fi
# Python 2.6.1
alias mkve26='mkvirtualenv --no-site-packages'
# Python 2.7.1
alias mkve='mkvirtualenv --no-site-packages --python=/usr/local/Cellar/python/2.7.1/bin/python'
alias mkveqt='mkvirtualenv --python=/usr/local/Cellar/python/2.7.1/bin/python'
alias designer='open /usr/local/Cellar/qt/4.7.2/bin/Designer.app'
# Python 3.2
alias mkve3='mkvirtualenv --no-site-packages --python=/usr/local/Cellar/python3/3.2/bin/python3'
# Ammend python path for Homebrew PyQt
export PYTHONPATH=/usr/local/lib/python:$PYTHONPATH
The first couple of sections set up the Terminal for bash completion and virtualenvwrapper commands. The third section sets up my virtualenv aliases: one for the default system python, one for Python 2.7, one for Python 2.7 and PyQt, and another for Python 3.2. Python 3 support was added to virtualenv in version 1.6, so you no longer need to jump through hoops to get it working with Pythyon 2.x.
Python 3 with Virtualenv and Macports
Update: As of virtualenv 1.6, Python 3 is supported out of the box, so all this is no longer necessary. I touch on it briefly in this post.
In my last post, I described how to get all the various versions of Python currently supported by Macports working together on OSX with virtualenv and virtualenvwrapper. There was one small problem, though. If you tried to create a new virtual environment with Python 3, you’d encounter this error:
$ mkvirtualenv --no-site-packages --python=/opt/local/bin/python3.1 bar
Running virtualenv with interpreter /opt/local/bin/python3.1
File "/Library/Python/2.6/site-packages/virtualenv-1.5.1-py2.6.egg/virtualenv.py", line 17
except ImportError, e:
^
SyntaxError: invalid syntax
This occurs because the except syntax has changed in Python 3, and setuptools, pip, and virtualenv haven’t been updated as yet. However, we can still get Python 3 to play nice with virtualenvwrapper. With Brandon Rhode’s virtualenv3 fork and a bit of bash profile arcanum, we can get Python 3 to play nice with virtualenvwrapper and the other versions of Python installed on our system.
First, go grab virtualenv3 from bitbucket and install it using Python 3. The example below assumes you’ve installed Python 3.1 and python_select via macports as described in my last post, and that the default Snow Leopard Python 2.6.1 is active.
sudo python_select python31 hg clone http://bitbucket.org/brandon/virtualenv3 cd virtualenv python setup.py develop sudo python_select python26-apple
Now open your bash ~/.profile in an editor and add the following aliases and functions:
alias mkve24='mkvirtualenv --no-site-packages --python=/opt/local/bin/python2.4'
alias mkve25='mkvirtualenv --no-site-packages --python=/opt/local/bin/python2.5'
alias mkve26='mkvirtualenv --no-site-packages --python=/opt/local/bin/python2.6'
alias mkve27='mkvirtualenv --no-site-packages --python=/opt/local/bin/python2.7'
function mkve31() {
/opt/local/bin/python3.1 /Users/daledavis/Source/virtualenv3/virtualenv3.py --no-site-packages $WORKON_HOME/$@
}
This assumes you have virtualenvwrapper installed with the WORKON_HOME environment variable. Also note that the mkve31 function body is all on one line despite what my skinny WordPress theme might suggest.
Now we should be able to create virtual environments with all the installed Python versions without hang up. Open up a new terminal and try creating a Python 2.7 and Python 3.1 virtual environment. If all is as it should be, you should see something very similar to what I’ve pasted below.
$ mkve27 py27 Running virtualenv with interpreter /opt/local/bin/python2.7 New python executable in py27/bin/python Installing setuptools............................done. virtualenvwrapper.user_scripts Creating /Users/daledavis/VirtualEnvs/py27/bin/predeactivate virtualenvwrapper.user_scripts Creating /Users/daledavis/VirtualEnvs/py27/bin/postdeactivate virtualenvwrapper.user_scripts Creating /Users/daledavis/VirtualEnvs/py27/bin/preactivate virtualenvwrapper.user_scripts Creating /Users/daledavis/VirtualEnvs/py27/bin/postactivate virtualenvwrapper.user_scripts Creating /Users/daledavis/VirtualEnvs/py27/bin/get_env_details (py27)$ mkve31 py31 New python executable in /Users/daledavis/VirtualEnvs/py31/bin/python Installing setuptools..............................................................................................................................................................................................................................................................................................................................done. (py27)$ python --version Python 2.7 (py27)$ workon py31 (py31)$ python --version Python 3.1.2

