In one of the Rails 2 web applications that I was working on, we use Postmark email delivery service for web apps, to handle our email delivery. And the Rails gem used in this case is the postmark-rails which is a drop-in plug-in for ActionMalier to send emails via Postmark.
The postmark-rails gem works great when you have a single default server for your application. However when you have multiple Postmark servers and you want to be able to selectively choose which of your ‘servers’ to use for delivery for different email category, there is no easy way to do that, at the time of this writing. I have spent hours looking for a solution over Google but no success.
For a single server, you set the api_key in the environment.rb file. Theoretically to use a different server, one just need to change the api_key before sending the email. With some testing, I found that could be done as follows:
Postmark.api_key = “new_api_key”
However it didn’t quite work the way I thought it would. If this is the very first attempt to send an email, setting to a new api_key will work just fine. But subsequent changing of the api_key will have no effect. The api_key used for the first email will now be used every time.
I checked to make sure that the Postmark.api_key attribute did change as I intended, and it does have the new value. It seemed like the api key is cached somewhere and subsequent change have no effect.
After digging through the gem source codes I finally found the reason why. According to the Postmark documentation, in order to authenticate yourself to the Postmark service, you need to send the correct HTTP header with the API key of your server. That header is:
X-Postmark-Server-Token: your-api-key-here
Postmark-rails gem takes care of that for you by using the value you set in the environment.rb file . The way it does that is by this line of code:
@headers ||= HEADERS.merge({ “X-Postmark-Server-Token” => Postmark.api_key.to_s })
(which is found in postmark-gem/lib/postmark/http_client.rb)
So the first time changing the api_key using Postmark.api_key = “new_api_key” it works fine because @headers at that point was nil, and hence it merges the api_key to the HEADERS constant and assigns it to @headers instance variable.
Subsequent changing the api_key will not work any more because the @headers instance variable at this point has already been set and hence will always be returned as the header.
So the workaround to overcome that would be to set the @headers instance variable to nil before changing the api_key value. I created a simple method to switch servers:
def switch_postmark_server(api_key)
Postmark::HttpClient.instance_variable_set(:@headers, nil)
Postmark.api_key = api_key
end
You call this method just before you execute the mailer delivery. If you generally have a default server that you use, then you switch it back to the default api_key after the mailer delivery.
There is probably a better way to go about it. In any case it is a quick hack to accomplish what I needed.