Implementation of feature using which PublicLab users can comment directly on the node(question ,research note,event) just by replying to the email(notification email which users recieve on creation of new node)
Mailman gem - A microframework for processing incoming email.
-
Add
mailman
gem to the Gemfile -
Mailman will run in its own process I will write a script to run it in the application’s script directory.I am referencing it as mailman_server
-
Initially, mailman_server script will look something like this :-
#!/usr/bin/env ruby
require "rubygems"
require "bundler/setup"
require "mailman"
Mailman::Application.run do
default do
puts "Received: #{message.subject}"
end
end
We start the server by calling Mailman::Application.run and pass it a block. In this block we define what Mailman calls routes. These determine how the incoming mail is handled. We’ve used a default route in above example which will be called for every email that’s recieved. Now, how the replied emails sent by users are fetched here so that those emails can be used to generate comments after processing 😯
Here comes role of mailman gem - Mailman provides us 3 reciever options : POP3, IMAP, HTTP .I would be discussing POP3 in this page. Now,setting up the POP3 configuration is also simple.This is the example:-
Mailman.config.pop3 = {
server: 'pop.gmail.com',
port: 995,
ssl: true,
username: ENV["GMAIL_USERNAME"],
password: ENV["GMAIL_PASSWORD"]
}
I have also made an demo video and a website of fetching of emails using mailman gem
Website link: https://mail-man-test.herokuapp.com/
Demo video link: https://www.youtube.com/watch?v=gMV4n4Hs7OA
Instead of defining routes here in the script ,I will redirect the mails to the function in a Model where inside the function email is processed i.e., corresponding nid
(node ID) is found using subject of the recieved email, we can use REGEX Expression to decode the nid or can also be done by equating the title of node with subject of email, after performing some operations on subject.Example of Model recieving method :-
class Article < ActiveRecord::Base
def self.receive_mail(message)
article_id = message.subject[/^Update (\d+)$/, 1]
if article_id.present?
Article.update(article_id, body: message.body.decoded)
else
Article.create! subject: message.subject, body: message.body.decoded, from: message.from.first
end
end
end
4.1 After the node is found the recieved email's body is used for creating the content of the comment 4.2 Using sender's email ID ,user is found from database. 4.3 A boolean term is also added in database and marked true if comment is generated through this process so that at time of rendering comments an email symbol can be attached. Finally, a new comment in the name of user,containing the email body corresponding to the node would be created successfully 🎉.
Logging is always beneficial and can come to our rescue anytime so I would enable logging by setting Mailman.config.logger
to a Logger instance. Example:
Mailman.config.logger = Logger.new('logs/mailman.log')
Polling is the process of checking for the new emails from the server. By default, polling time is 60 seconds i.e., arrival of new emails in the account(gmail account) is checked after every 60 seconds.We can easily change the polling time by mentioning poll interval like this :
Mailman.config.poll_interval = 90 # setting poll interval as 90 seconds
What if some error pops up due to some bad/uncompatible email then what would happen,mailman server would crash in no time 😱 . We can validate in model function that comment is created only if node is found and many other validations.But, to be sure that server doesn't crash, we can add rescue clause to avoid any such instance,so that solves our problem 😄. Example:
Mailman::Application.run do
default do
begin
Article.receive_mail(message)
rescue
Mailman.logger.error "Exception occurred while receiving message:\n#{message}"
Mailman.logger.error [e, *e.backtrace].join("\n")
end
end
And,that completes the comment creation process using the recieved email.The resultant script would look something like this:
# script/mailman_server
#!/usr/bin/env ruby
require "rubygems"
require "bundler/setup"
require "mailman"
Mailman.config.logger = Logger.new("log/mailman.log")
Mailman.config.pop3 = {
server: 'pop.gmail.com',
port: 995,
ssl: true,
username: ENV["GMAIL_USERNAME"],
password: ENV["GMAIL_PASSWORD"]
}
Mailman::Application.run do
default do
begin
Article.receive_mail(message)
rescue Exception => e
Mailman.logger.error "Exception occurred while receiving message:\n#{message}"
Mailman.logger.error [e, *e.backtrace].join("\n")
end
end
end
I have also made the demo video and website of the Reply by email to comment functionality.Please try it out and leave your comments below:
Demo Video link: https://youtu.be/b768EOUf6sg
Demo website link: https://mail-man-test.herokuapp.com/articles
Firstly, the subject of the email received is checked and node ID is extracted from the subject. If subject is proper and node ID exists in database then Email ID is searched in database.In case the Email ID is not found then , an automated email would be sent to the unidentified user prompting him to sign up or update his profile with latest Email ID, so in automated Email all these steps would be presented to them.
If someone tries to spam our mailbox by sending multiple emails having same body then,an email would be send to moderator for marking user's profile as spam.Also,some user may try to send multiple emails with different body in that case body of the email is checked.Discussion on this can be done.
As many email clients still allow sending email with empty body so we have to handle them too. In this case too, we can send automated reply to the user if he is identified - humbly asking them to include text in the email body.