fetchmailを用いて自動メール送信作ってみた

アドベントカレンダークリスマスイブ担当koniaです。

## 自己紹介
この会社に入り本格的にエンジニアとして働き出して早１年目、まだまだ足りないもの感じながらしごかれて最後には星になります。そんな若輩者の拙い文章ですが、ちょっとした時間に読んでいただき１つでも為になったら心中でワルツが踊り出します。

## ふとした依頼
さて、自己紹介はこれくらいにして最近サークルの後輩からこういう依頼が来ました。
「最近イベントとかするんですけど、そのメールを自動で返信してくれるシステム的なの欲しいんですよ…」
「サクッと作れないですかね」
お、これは作るしかないと。いろんなサービスが今や横行していますが、なんかちょっとエンジニアチックに作りたいなと思って色々みていました。
そこで見つけたのが、fetchmailというOSSです。
>リモートのメールサーバからメールを取得し、 これをローカル (クライアント) マシンの配送システムに転送します。 受け取ったメールは普通のメールユーザエージェントで扱うことができます。

https://linuxjm.osdn.jp/html/fetchmail/man1/fetchmail.1.html
こちらを参照

と言ったようにメールを扱うOSSがありましたのでこちらを使用していきます。



## 自動メール送信
OSS : fetchmail
OS  : Ubuntu 18.04
言語 : Ruby
OS、言語選定については後輩がわかるものに揃えた為、特に理由があったわけではないので他でもできます。

fetchmail設定ファイルについて

```
    #86400秒(24時間)ごとに起動する
    set daemon 86400

    defaults
     uidl
     no mimedecode
     no rewrite
     # メールを渡すプログラムのフルパス
     mda /home/name/process/textProcessing.rb
    keep

    ＃メールサーバの情報
    poll mail.example.jp protocol POP3
     username example@example.jp
     password xxxxxxxx
    ssl
```

特定の時間がきた場合、textProcessing.rbが起動するようになってます。
次にtextProcessing.rbのコードを示します。
このコード内部で行なっているのはイベント登録に来たメールからデータを取得し、CSV吐き出しにしています。（今回はDBを用いていません。）

```
  #! /usr/bin/ruby
  # coding: utf-8
  #-------------------------------------------------
  # Ruby script to get a mail via alias of postfix.
  #-------------------------------------------------

  require 'mail'
  require 'csv'

  class GetMail
    def initialize
      ＃csvの格納場所
      @out_csv = "/home/konia/deskTop/mail.csv"
    end

    #　イベント登録した際の学生情報メールを改行とコロンによって情報を配列化
    def execute
      CSV.open(@out_csv, "a") do |f|
        mail = Mail.new($stdin.read.gsub(/\r?\n/,"\r\n"))
        mail_sender = mail.from.first
        mail_subject = mail.subject.to_s
        mail_body = mail.body.to_s
        mail_body = mail_body.force_encoding("utf-8")
        mail_array = mail_body.scan(/:\s*([^\r]*)/)
        if mail_array.length >= 7 && mail_sender == "hoge@gmail.com" && mail_subject.scan("event").empty?
          date = mail_array[6].to_s.scan(/(\d+[^\(])/)
  	time = date[3]
      date.slice!(3,2)
      mail_array[6] = date.join
  	mail_array[7] = time
    # 配列化した情報をcsvで取り込む
          f << mail_array.flatten
        end
      end
    rescue => e
      $stderr.puts "[#{e.class}] #{e.message}"
      e.backtrace.each{|trace| $stderr.puts "\t#{trace}"}
      exit 1
    end
  end

  exit unless $0 == __FILE__
  GetMail.new.execute
```

そこから次はメールを送信する際の処理を下記に示します。
CSVから特定のデータを取得し、それを整形し特定の日付になった際にメール送信を行う。

```
#! /usr/bin/ruby
  # coding: utf-8
  #-------------------------------------------------
  # Ruby script to get a mail via alias of postfix.
  #-------------------------------------------------

  require 'mail'
  require 'csv'
  require 'time'

  class TextProcess
    def initialize
      @@from_mail = '送信者'
      @@to_mail = '受信者'
      @csv = "/home/hashi/deskTop/mail.csv"
    end

  # csvファイルから時間帯のデータを取ってき、イベント3日前と前日についての学生をまとめる
    def mailProcess
      student_info = {}
      flg_3 = i = 0
      CSV.foreach(@csv) do |cs|

        date = Time.strptime(cs[6].to_s,'%Y年%m月%d日')
        today = Time.now
        three_date_before = date - 259200
        two_date_before = date - 172800
        one_date_before = date - 86400
        if three_date_before <= today && today < two_date_before
          flg_3 = 1
  	student_info[i] = cs
  	i += 1
        elsif one_date_before <= today && today < date
  	sendMail(2,cs)
        end
      end
      if flg_3 == 1
        processed_text = textProcess(student_info)
        sendMail(1,processed_text)
      end
    end

    # 上記のイベント前に合致する学生情報をメールの本文に作成する
    def textProcess(tmp)
      i = 0
      info = ""
      for j in 0...tmp.length  do
        info << "氏名:#{tmp[j][0].to_s}\nメールアドレス:#{tmp[j][4].to_s}\n会場:#{tmp[j][5].to_s}\n日時:#{tmp[j][6].to_s+tmp[j][7].to_s}\n\n\n"
        i += 1
      end
      return info
    end

    # 作成したメールについて送信を行う
    def sendMail(flg,tmp)
      if flg == 2
        mail = Mail.new do
          from      @@from_mail
          to        @@to_mail
          cc        @@to_mail2
          bcc       @@to_mail3
          subject   "前日のお知らせです"
          body      "氏名:#{tmp[0].to_s}\nメールアドレス:#{tmp[4].to_s}\n会場:#{tmp[5].to_s}\n日時:#{tmp[6].to_s+tmp[7].to_s}"
        end
      elsif flg == 1
        mail = Mail.new do
          from      @@from_mail
          to        @@to_mail
  	      cc        @@to_mail2
          bcc       @@to_mail3
          subject   "3日前のお知らせです"
          body      tmp
        end
      end
      mail.charset = 'utf-8'
      mail.delivery_method(:smtp,
        address:        "送信サーバ",
        port:           ポート番号,
        domain:         "ドメイン名",
        authentication: :login,
        user_name:      "メールアドレス",
        password:       "送信サーバのパスワード",
        enable_starttls_auto: false
      )
      mail.deliver
    end
  end

  exit unless $0 == __FILE__
  TextProcess.new.mailProcess

```

以上となります。OSS使って書いてみると色々と気づくものもありますが今の時代なんでもそろってるからそっちを使った方が楽なのは間違いないですね😇