Last month before RailsConf Luke Francl and I published "MMS2R : Making email useful" on PeepCode. Its a PDF book so kill all the trees that you can buying it. The book is awesome because of the diversity of experience that Luke brings to the book and Geoffrey Grosenbach is a fabulous editor.
We cover a wide range of experience dealing with MMS in Rails and other applications. An overview is:
- Introduction (protocol, mobile networks, gateways, etc.)
- A Brief History (MMS integrated with web apps, etc.)
- Processing MMS
- Working with ActionMailer (e.g. Rails, daemonizing Rails, IMAP & POP fetching)
- Testing (Test::Unit & RSpec)
- Advanced Topics
MMS2R handles more than just MMS
You may not be aware of this but MMS are just multi-part MIME encoded email. And Luke likes to say that MMS2R is good for email in general not just MMS. MMS2R pulls apart multipart email in an intelligent manner and gives you access to its content in an easy fashion. It writes each part decoded to temporary files and provides a duck typed CGI File so that it is easily integrated with attachment_fu.
Pimp my WWR
I put a lot work into MMS2R so that its easy to access user generated content in an intelligent fashion. Recommend me on Working With Rails if you’ve benefited from this experience and thank you in advance!
Friends of MMS2R
MMS2R and our book would not have been possible without the help of these awesome people from the open source community:
If you are starting to get a cluttered model space in your Rails application
you should consider placing your models in a namespace. As an example I’m
going to go through a Rails application I’m calling Recipes. If my
models were starting to have the namespace implied in the class names such as
AppleFruit in app/models/apple_fruit.rb then that’s starting to smell like
rotten apples. A better namespace would be Fruit::Apple in app/models/fruit/apple.rb
This is what we’ll be modeling. Fruits of Apples and Oranges via single table
inheritance. And Vegetables of Potatoes and Carrots through single table
We’ll have Ingredients that belong to Fruit, Vegetables, and Recipes.
Ingredients are a limited kind of join model going from the recipe through
to the kind of ingredient (i.e. fruit or vegetable). Ingredients are a true
join model from the fruit or vegetables back to their associated recipes.
The Ingredient is polymorphic because Fruits and Vegetables are different kinds of
Finally Recipes are another single table inheritance model but by
convention they will only have ingredients, they won’t be associated
to the kinds of ingredients through the polymorphic Ingredient class.
To access the specific kinds of ingredients from the recipe’s perspective
you must access the collection of ingredients and then program the desired
behavior to access the kinds of ingredients in your application logic.
Here’s a graph of the models we are designing (click for bigger picture):
All of the source for this example as available at the following Subversion
svn checkout http://svn.mondragon.cc/svn/recipes/trunk/ recipes
mms2r version 1.0.7 has been released!http://mms2r.rubyforge.org/
MMS2R is a library that decodes the parts of an MMS message to disk while
stripping out advertising injected by the cellphone carriers. MMS messages are
multipart email and the carriers often inject branding into these messages. Use
MMS2R if you want to get at the real user generated content from a MMS without
having to deal with the garbage from the carriers.
If MMS2R is not aware of a particular carrier no extra processing is done
to the MMS other than decoding and consolidating its media.
Contact the author to add additional carriers to be processed by the
library. Suggestions and patches appreciated and welcomed!
Corpus of carriers currently processed by MMS2R:
- AT&T/Cingular => mmode.com
- Cingular => mms.mycingular.com
- Cingular => cingularme.com
- Dobson/Cellular One => mms.dobson.net
- Nextel => messaging.nextel.com
- Sprint => pm.sprint.com
- Sprint => messaging.sprintpcs.com
- T-Mobile => tmomail.net
- Verizon => vzwpix.com
- Verizon => vtext.com
== 1.0.7 / 2007-04-27 (Senator Stampingston)
- patch submitted by Luke Francl
- added a get_subject method that returns nil when any MMS has a default carrier subject
- get_subject returns nil for ‘’, ’Multimedia message’, ‘(no subject)’, ‘You have new Picture Mail!’
Cellphone Multimedia Message Service (MMS) messages that your cellphone sends are really just email formatted text. You can send MMS to other cellphones or to a real email address. I wrote a post about using the Rails receive method in ActionMailer::Base to process email decoding email attachments with ActionMailer::Base receive If you just want to process the mail but don’t need the hook into Rails then just use the TMail class’s parse method directly
mail = TMail::Mail.parse(raw_email)
I’ve been processing MMS emails via TMail recently and have found the cellphone carriers often modify user generated content (text, videos, images) to include advertising for their services.
If you want to have control over the version of ruby that is available in your user space here’s how to build and install it in your $HOME directory. The Debian Way of packaging ruby and gem deviates from the Ruby Way on other Nix platforms. So its better to just do it Your Way so that you have control of which ruby and ruby tools (gem, rake, rails, etc.) is available to your user environment.
This is a way to compile and install ruby 1.8.5 with local dependency on openssl, readline, and openssl on Debian (Etch/testing) 686 in your $HOME directory. The method also works for FreeBSD 4.8-STABLE. (BTW if you have root privilege on your machine and you just want to enable openssl to your already installed ruby make sure the libopenssl-ruby Debian package is installed and ignore the rest of the knowledge presented here.)
Not saving a yaml file after calling YAML::dump cost me about two hours the other day. Here’s an example:
# load fnm='myyaml.yml' h = YAML::load_file(fnm) || Hash.new # add to hash h[:foo]='bar' #save# load
h = YAML::load_file(fnm) || Hash.new
# add to hash
- don’t do it like this …
f = File.open(fnm, ‘w’)
#close writes the file to disk
# file gets closed after block executes
File.open(fnm, ‘w’) do |out|
|I’ve started reading the second edition of Agile Web Development with Rails . I’m going to try something different and append my notes from each chapter to his blog entry as I read them. I bought this book from The Pragmatic Programmers site with the PDF copy of the book. I like having the PDF copies of their books (I currently own the PickAxe book , the Agile Rails book, and the Rail Recipes books) so I can reference them without having to search the internet or crack open my real book for a discussion of a question I might have.|
There are lots of references that say you can decode images and other media attachements in email using the receive method of ActionMailer::Base
Ruby On Rails Wiki is one: HowToReceiveEmailsWithActionMailer.
Rails Recipes Recipe #68 “Testing Incoming Mail” is another.
But those references and many others on the internet don’t show you how to really do it.
Here’s how its done …
The title to this blog entry is a bit misleading. This is really my notes on the implementing Curtis Hibbs’ “Rolling with Ruby on Rails” part 1 and part 2 . This is not a tutorial in and of itself but is a supplement to Curtis’s work. There must be ways to improve my code as well, so I look forward to learning from someone’s Cookbook4. My work can be found in the cookbook3.tar.bz2 file.
This is a quick set of subversion commands to create a repository for your Rails application. The repository is dedicated to your Rails app so the head of your source will be in the trunk, version releases will be in tags, and branches for you code base will be in branches.
Nicholas Evan’s Subversion In Fifteen Minutes is a good reference for quick subversion setup, what your getting here is the 5 minute version with Rails specifics. The HowtoUseRailsWithSubversion page at RubyOnRails goes into more detail about additional things to consider when sharing a Rails project across many developers (like how you might handle database.yml for example).