SoFunction
Updated on 2025-04-07

Ruby implements the trigger program for active email push

After the mail server receives the email, the service pushes the notification program. Is there any way to achieve it?

1. Client polling
2. The server actively pushes.

First, let’s get familiar with the protocol for sending and receiving emails:
Net::SMTP (send email)
Net::POP3 (receive emails)
Net::IMAP (receive mail)

There are many examples of receiving emails using pop3, but receiving emails using pop3 can only get all the emails in the inbox. Tags such as whether the email has been read and cannot be obtained. Using the imap protocol avoids this embarrassment. Imap not only can obtain detailed information of an email (such as whether it has been read and whether it has been replyed), but it also allows users to change the email tag. However, there are not many email servers that support the imap protocol. I only know 21cn and gmail. The following example uses multiple contents of proxy and SSL authentication. Please refer to it.

Imap emails are all requested on demand. That is to say, when you get a Message object, there is actually no information in it. When you use the get method to obtain information in this object, such as getSubject, the Message object will revisit the mail server to get the message. Therefore, before you get all the required information, you cannot close the directory, and you cannot disconnect. If you really want to operate the Message object after closing the directory or connecting, you need to use the fetch method of the Folder object to get the required information.

1: Client polling

Here is a pop3 and imap example of polling access to get emails:

POP3 Polling:

Copy the codeThe code is as follows:

loop do
require 'net/pop'
pop = Net::('EMAILSERVICE')
('USENAME', 'PASSWORD')           
if ?
  puts 'No mail.'
else
  pop.each_mail do |m|
    do |chunk|  
      p chunk
    end
  end
  puts "#{} mails popped."
end

sleep(10)
end

imap polling:

Copy the codeThe code is as follows:

loop do
require 'net/imap'
imap = Net::('EMAILSERVICE')
"USERNAME", "PASSWORD"
('INBOX')
(["BEFORE", "29-Oct-2014", "SINCE", "28-Oct-2014"]).each do |message_id|
   envelope = (message_id, "ENVELOPE")[0].attr["ENVELOPE"]
   puts "#{[0].name}: \t#{}"
end
sleep(10)
end

Two: The server actively pushes

The following implements a server active push method: ()

This is a technology between pull and Persistent TCP/IP: long polling. The principle is that every time the client requests the service, the server holds it. After a message returns or time out, it will initiate a request again and wait for the message to arrive. This mode does not require the heartbeat to keep the heartbeat, nor does it require continuous TCP occupation, and is more suitable for the push of timely messages on the page side.

Copy the codeThe code is as follows:

SERVER = 'EMAILSERVICE'
USERNAME = 'USERNAME'
PW = 'PASSWORD'
require 'net/imap'

# Extend support for idle command. See online.
# /topic/50828
# /jem/2783772
# but that was wrong. see /opt/ruby-1.9.1-p243/lib/net/.
class Net::IMAP
  def idle
    cmd = "IDLE"
    synchronize do
      @idle_tag = generate_tag
      put_string(@idle_tag + " " + cmd)
      put_string(CRLF)
    end
  end

  def say_done
    cmd = "DONE"
    synchronize do
      put_string(cmd)
      put_string(CRLF)
    end
  end

  def await_done_confirmation
    synchronize do
      get_tagged_response(@idle_tag, nil)
      puts 'just got confirmation'
    end
  end
end

class Remailer
  attr_reader :imap

  public
  def initialize
    @imap = nil
    @mailer = nil
    start_imap
  end

  def tidy
    stop_imap
  end

  def print_pust
       envelope = @(-1, "ENVELOPE")[0].attr["ENVELOPE"]
       puts "From:#{[0].name}\t Subject: #{}"
  end

  def bounce_idle
    # Bounces the idle command.
    @imap.say_done
    @imap.await_done_confirmation
    # Do a manual check, just in case things aren't working properly.
    @
  end

  private
  def start_imap
    @imap = Net::('')
    @ USERNAME, PW
    @ 'INBOX'

    # Add handler.
    @imap.add_response_handler do |resp|
      if resp.kind_of?(Net::IMAP::UntaggedResponse) and == "EXISTS"
        @imap.say_done
        do
          @imap.await_done_confirmation
          print_pust
          @
        end
      end
    end
    @
  end

  def stop_imap
    @
  end

end

begin
  Net:: = true
  r =
  loop do
    puts 'bouncing...'
    r.bounce_idle
    sleep 15*60
#Generally set to keep the long link without operation for 15 minutes
  end
ensure
 
end