• Sending emails using Google Mail with Ruby

    It's no secret that Google Mail has become, over the last years, the most widely used email server and client on the world. Not only it's basically free, but with the use of Google Apps you can even use it on your own domains.

    Because so many people use it, even system administrators, it may be good to know how to use it to send system emails. Also, because Ruby is actually the only scripting language I feel comfortable with, I'll show you a simple library to send emails using Google SMTP server as an outgoing server, so you don't have to configure your server with sendmail, postfix or another typical UNIX mail server.

    The first thing we will need is to include (and install) two gems:

    • net/smtp (actually this comes from the Standard Library on Ruby 1.9)
    • tlsmail
    The first one will allow us to use some SMTP features in Ruby, and the second one will allow us to use TLS authentication for SMTP, the method used by Google Mail.

    With those two libraries, we can already send a simple email, using the standard SMTP format:

    def send_email from, to, mailtext
      begin 
        Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
        Net::SMTP.start(@smtp_info[:smtp_server], @smtp_info[:port], @smtp_info[:helo], @smtp_info[:username], @smtp_info[:password], @smtp_info[:authentication]) do |smtp|
          smtp.send_message mailtext, from, to
        end
      rescue => e  
        raise "Exception occured: #{e} "
        exit -1
      end  
    end

    You can see here that the SMTP info is stored in a variable @smtp_info. We will take care of that later. Also, the variable mailtext passed to the method also needs a special format. More on that later as well. The really important fragment of code here is the one that calls enable_tls on the Net::SMTP module. This method is provided by the tlsmail gem and will allow our SMTP connection to use TLS as the authentication method. The other part of the code is pretty straightforward: we simply call the start method with a block, in which we actually send the email with send_message. Note that we have to provide the start method with the SMTP info of our Google Mail server account. This includes the server, which will be smtp.gmail.com, the port, which is 587, the HELO, which is gmail.com if using a standard account or your domain FQDN if using your own domain, and finally your username and password. For the authentication parameter we have to provide :plain (TLS will be used on top of that).

    Now let's see how the mailtext string is built. In this case I'll be using a plain text format with two different variants: a simple text email, or an email with an attachment.

    To send a simple text email, we have to follow the SMTP standard. I took the info from this tutorialspoint post. Here's the pattern we have to follow to build a compliant string:

    def send_plain_email from, to, subject, body
      mailtext = <<EOF
    From: #{from}
    To: #{to}
    Subject: #{subject}
    
    #{body}
    EOF
      send_email from, to, mailtext
    end

    Note the importance of the indenting here, as the from/to/subject lines must start at the first text column. With this simple method, you can then simply call the method we programmed before with the resulting string as a parameter and the email will be sent. Pretty easy.

    Sending an attachment is a bit more complicated. As SMTP email is send in plain text, attachments are encoded in base64 strings, and are added to the message string in a special way. Here's how to do it in Ruby:

    def send_attachment_email from, to, subject, body, attachment
    # Read a file and encode it into base64 format
      begin
        filecontent = File.read(attachment)
        encodedcontent = [filecontent].pack("m")   # base64
      rescue
        raise "Could not read file #{attachment}"
      end
    
      marker = (0...50).map{ ('a'..'z').to_a[rand(26)] }.join
      part1 =<<EOF
    From: #{from}
    To: #{to}
    Subject: #{subject}
    MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary=#{marker}
    --#{marker}
    EOF
    
    # Define the message action
      part2 =<<EOF
    Content-Type: text/plain
    Content-Transfer-Encoding:8bit
    
    #{body}
    --#{marker}
    EOF
    
    # Define the attachment section
      part3 =<<EOF
    Content-Type: multipart/mixed; name=\"#{File.basename(attachment)}\"
    Content-Transfer-Encoding:base64
    Content-Disposition: attachment; filename="#{File.basename(attachment)}"
    
    #{encodedcontent}
    --#{marker}--
    EOF
    
      mailtext = part1 + part2 + part3
    
      send_email from, to, mailtext
    end

    As you can see, in the first place the file is read and converted to a base64 string. After that, the message is generated. SMTP uses a special unique marker to delimit the attachment from the rest of the text. In here we use the line (0...50).map{ ('a'..'z').to_a[rand(26)] }.join (extracted from StackOverflow) to generate a 50 char length random string. Although it's very unlikely to happen, we should check that this random string does not appear anywhere else in the message body or the base64 converted attached file before using it as a delimiter.

    After that, the rest of the message is built, specifying it has an attachment and its delimiter in the following lines:

    MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary=#{marker}
    --#{marker}

    The file is actually attached some lines below. After that, we can pass this new string to the method that sends the email, and all done.

    Now, because our SMTP info can be sensitive (it contains our username and our password), it might not be a good idea to just hardcode this info in the email sending script. That's why I've used a yaml serialized hash to store this info, so we can load it at any time. Doing this is really easy with the yaml gem:

    smtp_info = 
        begin
          YAML.load_file("/path/to/your/smtpinfo")
        rescue
          $stderr.puts "Could not find SMTP info"
          exit -1
        end

    An example file would look like this:

    ---
    :smtp_server: smtp.gmail.com
    :port: 587
    :helo: gmail.com
    :username: user@gmail.com
    :password: your_password_here
    :authentication: :plain

    Now that we have all the parts programmed, we should only pack it a little so it can be of use as a library. The following code contains a simple script with a class to send the emails and a little program that reads parameters from the command line:

    require 'net/smtp'
    require 'tlsmail'
    require 'yaml'
    
    class SMTPGoogleMailer
      attr_accessor :smtp_info
    
      def send_plain_email from, to, subject, body
        mailtext = <<EOF
    From: #{from}
    To: #{to}
    Subject: #{subject}
    
    #{body}
    EOF
        send_email from, to, mailtext
      end
    
      def send_attachment_email from, to, subject, body, attachment
    # Read a file and encode it into base64 format
        begin
          filecontent = File.read(attachment)
          encodedcontent = [filecontent].pack("m")   # base64
        rescue
          raise "Could not read file #{attachment}"
        end
    
        marker = (0...50).map{ ('a'..'z').to_a[rand(26)] }.join
        part1 =<<EOF
    From: #{from}
    To: #{to}
    Subject: #{subject}
    MIME-Version: 1.0
    Content-Type: multipart/mixed; boundary=#{marker}
    --#{marker}
    EOF
    
    # Define the message action
        part2 =<<EOF
    Content-Type: text/plain
    Content-Transfer-Encoding:8bit
    
    #{body}
    --#{marker}
    EOF
    
    # Define the attachment section
        part3 =<<EOF
    Content-Type: multipart/mixed; name=\"#{File.basename(attachment)}\"
    Content-Transfer-Encoding:base64
    Content-Disposition: attachment; filename="#{File.basename(attachment)}"
    
    #{encodedcontent}
    --#{marker}--
    EOF
    
        mailtext = part1 + part2 + part3
    
        send_email from, to, mailtext
      end
    
      private
    
      def send_email from, to, mailtext
        begin 
          Net::SMTP.enable_tls(OpenSSL::SSL::VERIFY_NONE)
          Net::SMTP.start(@smtp_info[:smtp_server], @smtp_info[:port], @smtp_info[:helo], @smtp_info[:username], @smtp_info[:password], @smtp_info[:authentication]) do |smtp|
            smtp.send_message mailtext, from, to
          end
        rescue => e  
          raise "Exception occured: #{e} "
          exit -1
        end  
      end
    end
    
    if __FILE__ == $0
      from = ARGV[1]
      to = ARGV[2]
      subject = ARGV[3]
      body = ARGV[4]
      attachment = ARGV[5]
      smtp_info = 
        begin
          YAML.load_file(ARGV[0])
        rescue
          $stderr.puts "Could not find SMTP info"
          exit -1
        end
    
      mailer = SMTPGoogleMailer.new
      mailer.smtp_info = smtp_info
    
      if ARGV[4]
        begin
          mailer.send_attachment_email from, to, subject, body, attachment
        rescue => e
          $stderr.puts "Something went wrong: #{e}"
          exit -1
        end
      else
        begin
          mailer.send_plain_email from, to, subject, body
        rescue => e
          $stderr.puts "Something went wrong: #{e}"
          exit -1
        end
      end
    end

    And that's all! You can use the script as a standalone command to send an email with some command line arguments or just require it in your ruby script and use the class to send the messages.

  • Ruby on Rails, Varnish and user dependent content

    Ruby on Rails performance is a topic that has been widely discussed. Whichever the conclusion you want to make about all the resources out there, the chances you'll be having to use a cache server in front of your application servers are pretty high. Varnish is a nice option when having to deal with this architecture: it has lots of options and flexibility, and its performance is really good, too.

    However, adding a cache server in front of your application can lead to problems when the page you are serving has user dependent content. Let's see what can we do to solve this problem.

    Read on →

  • A Ruby implementation of the FizzBuzz test using the Enumerator class

    Some days ago I learnt about The FizzBuzz Test and did a simple implementation in Ruby. The FizzBuzz test is a simple algorithm that is supposed to do the following:

    For each number from 1 to 100:

    • If the number is divisible by 3, print "Fizz"
    • If the number is divisible by 5, print "Buzz"
    • If the number is divisible by both 3 and 5, print "FizzBuzz"
    • Otherwise print the number

    I was just reading about how you can use the Enumerator class to have generators in the Programming Ruby 1.9 book, and thought that a good implementation could be done using just an Enumerator, so here it is, along with a simple RSpect test:

    FizzBuzz = Enumerator.new do |yielder|
      count = 1
      loop do
        if count % 3 == 0
          if count % 5 == 0
            yielder.yield "FizzBuzz"
          else
            yielder.yield "Fizz"
          end
        elsif count % 5 == 0
          yielder.yield "Buzz"
        else 
          yielder.yield count
        end
        count += 1
      end
    end

    require_relative 'fizzbuzz'
    
    describe FizzBuzz do
      before(:all) do
        @fizzbuzzes = FizzBuzz.first(100)
      end
    
      it "returns 'Fizz' for all multiples of 3" do
        @fizzbuzzes[3-1].should == 'Fizz'
      end
    
      it "returns 'Buzz' for all multiples of 5" do
        @fizzbuzzes[5-1].should == 'Buzz'
    
      end
    
      it "returns 'FizzBuzz' for all multiples of 3 and 5" do
        @fizzbuzzes[60 - 1].should == 'FizzBuzz'
    
      end
    
      it "returns the passed number if not a multiple of 3 or 5" do
        @fizzbuzzes[1 - 1].should == 1
      end
    end

    You can also find the code in its GitHub repository: https://github.com/brafales/ruby-fizzbuzz.

  • Push git tags to a remote repository

    If you ever wondered how to push the tags you set locally to a remote repository in git, you can do it with the following simple command:

    git push --tags

  • Give your Ruby console a dash of colour

    When you're developing an application in Rails (or Ruby), you spend lots of time in the IRB, the Interactive Ruby Shell. Usually just to test some Ruby code, start an application console or debug something going on inside the project. Yesterday, looking at a coworker screen, I saw he had his console with lots of color hints, and I thought it was pretty nice. I asked him about that and he told me he was using a special gem for that.

    The gem is called wirble. It has some nice defaults and allows you to configure the colors as you wish. To use it in your consoles, just add this lines to your ~/.irbrc file:

    begin
      require 'rubygems'
      require 'wirble'
      Wirble.init
      Wirble.colorize
    rescue LoadError => err
      warn "Couldn't load Wirble: #{err}"
    end

    Of course, you'll need to install the gem. Just issue a gem install wirble and you'll be good to go!