BlackListing + Hotmail's spambox

Posted by John
on Wednesday, 19 March 2008

An annoying thing about building an email system is the fear of your server's IP getting accidentally logged on one of the many Anti-Spam blacklisting sites.

These site's basically record who they think is sending spam emails, so if they think you're one of the bad guys you go in their book; which as you can imagine services like GMail, YahooMail and Hotmail reference these to gauge bad senders.

To check if you've been unintentionally listed;

Most site's will allow you to request removal from their black-lists without too much of a problem.

Hotmail's SpamBox

Another thing i'm trying to figure out is how to stop emails my webapp sends from going into into Hotmail's spam box, it's ok with Gmail and everyone else, but bad with MS Hotmail.

'Hotmail have a propietry spam filter which is prone to false positives from some senders for no aparent reason. Hotmail wont tell you why it is classed as spam.'

Thankfully Thomas Glasgow has suggested that if you should first send an email from YahooMail to your site, then reply back to YahooMail; YahooMail should then interpret that as a good site and stop doing this.

Not sure whether it works for Hotmail but worth a shot.

Rails : Exception Catching

Posted by John
on Thursday, 06 March 2008

Global Error Catching

To handle errors globally in your application, add..

(within application.rb) def rescueactionin_public(exception) render :text => "

There was a global error processing your request.

" end def local_request? false end

The final def def local_request? tells rails that it should act the same way in development mode.

Local Error Catching

To catch errors locally within your form submits do...

def update return unless request.post? begin User.update(self.current_user.id, params[:user]) render :action => 'success' rescue ActiveRecord::RecordInvalid flash[:notice] = "Sorry, your profile was not saved" render :action => 'profile'
rescue flash[:notice] = "Sorry, something went wrong" render :action => 'profile' end end

Simple process, here we're basically saying if the user has submitted form data (done a POST), then process the code; if not redirect back to the sending page.

If yes then update the User object relevant to the specific user record (found by the id), updating the record with the parameters from the form. Save the record and render the 'success' page.

If we get a problem with saving the record (activerecord), display a message and goto the 'profile' page.

If we get some other error, display the second message and goto the 'profile' page.

Notify Me of Errors via Email

On top of this you can enhance it with flash messages and send off an email with the error code, here's one such way.

(in application.rb) protected

def log_error(exception) super(exception)

begin
    Alert.deliver_errormail(
      exception, 
      clean_backtrace(exception), 
      @session.instance_variable_get("@data"), 
      @params, 
      @request.env)
rescue => e
    logger.error(e)
end

end

Adding this makes it send error emails in development mode..

def local_request? false end

Now create an Mailer object with...

script/generate mailer Alert

And put this code in your generated alert.rb file

class Alert < ActionMailer::Base def errormail(exception, trace, session, params, env, sent_on = Time.now) content_type "text/html" @recipients = 'john@gmail.com' @from = 'admin@mysite.com' @subject = "[Error] exception in #{env['REQUEST_URI']}" @senton = senton @body["exception"] = exception @body["trace"] = trace @body["session"] = session @body["params"] = params @body["env"] = env end end

And create a appropriate alert/errormail.rhtml file in your view for the formatted error email...

Error report from <%= Time.now %>

<% if @session['user'] -%> <% end -%>
Message<%= @exception.message %>
Location<%= @env['REQUEST_URI'] %>
Action<%= @params.delete('action') %>
Controller<%= @params.delete('controller') %>
Query<%= @env['QUERY_STRING'] %>
Method<%= @env['REQUEST_METHOD'] %>
SSL<%= @env['SERVER_PORT'].to_i == 443 ? "true" : "false" %>
Agent<%= @env['HTTP_USER_AGENT'] %>
User id<%= @session['user'].id %>
User name<%= @session['user'].name %>
User email<%= @session['user'].email %>
Registered<%= @session['user'].created_at %>

Backtrace

<%= @trace.to_a.join("

\n

") -%>

Params


<% for key, val in @params -%>

<%= key %>

<%= val.to_yaml.to_a.join("

\n

") %>

<% end if @params -%>

Session


<% for key, val in @session -%>

<%= key %>

<%= val.to_yaml.to_a.join("

\n

") %>

<% end if @session -%>

Environment


<% for key, val in @env -%> <% end if @env -%>
<%= key %> <%= val %>

Now whenever an error happens you'll get an email about it, good for the production environment.

Setup the Emailer

Remember to setup the emailer otherwise no emails will be sent.

By adding this to your environments/production.rb

config.actionmailer.raisedelivery_errors = true ActionMailer::Base.delivery_method = :sendmail ActionMailer::Base.sendmail_settings = { :location => '/usr/sbin/sendmail', :arguments => '-i -t' }

Or more detailed,

Setup a DNS MX Record so you don't get blacklisted!

A further note, remember to add an MX record for the domain your using otherwise your site will be blacklisted by anti-spam sites.

An MX record basically tells other sites where they should send emails to, it's like saying where the postman should deliver incoming letters.

Now if your only sending emails you shouldn't need this but as a previous commenter noted, most anti-spam sites blacklist you if your sending and don't have one; regardless of whether you want the site to receive emails or not. Hence you've got to include one.

A simple example is...

type: MX name: mysite.com data: ASPMX.L.GOOGLE.COM. auxilary info: 1

Now ok, this is actually telling anti-spammers your using Google Applications to handle your email (which isn't strictly true) but at least it get's them off your back until you setup your own full-blown POSTFIX mail server.

Which is something I'm working on writing an article for.

Expect that in a future posting.

Sending mail with Rails

Posted by John
on Monday, 05 November 2007

Finally managed to work this out, what follows is something that does 100% work!

Install your Mail Client

Choose which one you're gonna use, SendMail or the more powerful Postfix;

sudo aptitude install sendmail
..or
sudo aptitude install postfix

...however, for this example I'm going to be using the easier Sendmail.

Create your Mailer Model

First things first, your gonna need a mailer model, so to create one go to the root of your rails app and type...

script/generate mailer UserMailer

This will generate a couple of new directories but more importantly thru the magic of rails by using 'mailer' it will know that your creating a model that will use the ActionMailer library and so things will be handled differently with this one than other models.

Setup Rails to use SendMail

Now we could use SMTP to send emails from our web app, but to be perfectly honest that's like a major headache for the newbie to setup. So as long as your running this on a linux box you can use the more simpler SendMail libaries to send email.

To use these in production, edit your production.rb environment file...

myapp/config/environments/production.rb

and add these lines...

config.action_mailer.raise_delivery_errors = true

ActionMailer::Base.delivery_method = :sendmail

ActionMailer::Base.sendmail_settings = {
:location       => '/usr/sbin/sendmail',
:arguments      => '-i -t'
}

What the first line will do is notify you of any delivery errors, useful in testing, you can turn this off in production by setting it to false.

  • :location tells the actionmailer where to find the sendmail libraries, default location.

  • :arguments tell sendmail to send the email immediately, rather than wait, so your email does get sent.

That's that done, remember you could use SMTP but it can be a nightmare to setup installing postfix, setting your MX records etc. this however is simple & quick.

Back to our UserMailer model

Now that's all sorted, open your UserMailer model...

myapp/app/models/user_mailer.rb

And add...

def test
recipients  "user@destination.com"
from        "admin@source.com"
subject     "Thank you for Registering"
body        "test email"
end

What we've done is created a method that will email user@destination.com when it get's called.

Which can be done by using...

User_Mailer.deliver_test

...anywhere in our app's code.

Notice the deliver_ prefix in front of our method test. This is how we associate our 'magic' ActionMailer methods associated when we generated the model.

Further Reading

You can optionally expand this with the examples below, but hopefully the above has helped you get over one of the major headaches of Ruby on Rails.

Quick and Dirty Ruby Emailer

Posted by John
on Sunday, 04 November 2007

By no means perfect, here's a tiny slice of ruby-on-rails code to send emails...

Net::SMTP.start('localhost') do |smtp|
smtp.send_message 'hello...', 'yourdomain.com', @user.email
end

Remember to setup your email server Postfix, which this guide will help you out.

More to come later, with a proper class-based emailer; waiting for my MX records to propogate...