sisimai 4.14.2
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sisimai might be problematic. Click here for more details.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +165 -0
- data/.travis.yml +21 -0
- data/ANALYTICAL-PRECISION +54 -0
- data/Changes +5 -0
- data/Developers.mk +129 -0
- data/Gemfile +9 -0
- data/LICENSE +26 -0
- data/Makefile +56 -0
- data/README.md +300 -0
- data/Rakefile +7 -0
- data/Repository.mk +69 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/lib/sisimai.rb +60 -0
- data/lib/sisimai/address.rb +218 -0
- data/lib/sisimai/arf.rb +343 -0
- data/lib/sisimai/data.rb +413 -0
- data/lib/sisimai/data/json.rb +36 -0
- data/lib/sisimai/data/yaml.rb +32 -0
- data/lib/sisimai/datetime.rb +518 -0
- data/lib/sisimai/mail.rb +82 -0
- data/lib/sisimai/mail/maildir.rb +85 -0
- data/lib/sisimai/mail/mbox.rb +69 -0
- data/lib/sisimai/mail/stdin.rb +52 -0
- data/lib/sisimai/mda.rb +152 -0
- data/lib/sisimai/message.rb +510 -0
- data/lib/sisimai/mime.rb +127 -0
- data/lib/sisimai/msp.rb +54 -0
- data/lib/sisimai/msp/de/einsundeins.rb +174 -0
- data/lib/sisimai/msp/de/gmx.rb +197 -0
- data/lib/sisimai/msp/jp/biglobe.rb +179 -0
- data/lib/sisimai/msp/jp/ezweb.rb +292 -0
- data/lib/sisimai/msp/jp/kddi.rb +195 -0
- data/lib/sisimai/msp/ru/mailru.rb +306 -0
- data/lib/sisimai/msp/ru/yandex.rb +241 -0
- data/lib/sisimai/msp/uk/messagelabs.rb +250 -0
- data/lib/sisimai/msp/us/amazonses.rb +248 -0
- data/lib/sisimai/msp/us/aol.rb +234 -0
- data/lib/sisimai/msp/us/bigfoot.rb +243 -0
- data/lib/sisimai/msp/us/facebook.rb +306 -0
- data/lib/sisimai/msp/us/google.rb +357 -0
- data/lib/sisimai/msp/us/outlook.rb +243 -0
- data/lib/sisimai/msp/us/receivingses.rb +247 -0
- data/lib/sisimai/msp/us/sendgrid.rb +257 -0
- data/lib/sisimai/msp/us/verizon.rb +311 -0
- data/lib/sisimai/msp/us/yahoo.rb +178 -0
- data/lib/sisimai/msp/us/zoho.rb +198 -0
- data/lib/sisimai/mta.rb +55 -0
- data/lib/sisimai/mta/activehunter.rb +155 -0
- data/lib/sisimai/mta/apachejames.rb +194 -0
- data/lib/sisimai/mta/courier.rb +307 -0
- data/lib/sisimai/mta/domino.rb +209 -0
- data/lib/sisimai/mta/exchange.rb +314 -0
- data/lib/sisimai/mta/exim.rb +549 -0
- data/lib/sisimai/mta/imailserver.rb +227 -0
- data/lib/sisimai/mta/interscanmss.rb +167 -0
- data/lib/sisimai/mta/mailfoundry.rb +173 -0
- data/lib/sisimai/mta/mailmarshalsmtp.rb +206 -0
- data/lib/sisimai/mta/mcafee.rb +201 -0
- data/lib/sisimai/mta/messagingserver.rb +241 -0
- data/lib/sisimai/mta/mfilter.rb +190 -0
- data/lib/sisimai/mta/mxlogic.rb +283 -0
- data/lib/sisimai/mta/notes.rb +206 -0
- data/lib/sisimai/mta/opensmtpd.rb +225 -0
- data/lib/sisimai/mta/postfix.rb +306 -0
- data/lib/sisimai/mta/qmail.rb +335 -0
- data/lib/sisimai/mta/sendmail.rb +317 -0
- data/lib/sisimai/mta/surfcontrol.rb +193 -0
- data/lib/sisimai/mta/userdefined.rb +148 -0
- data/lib/sisimai/mta/v5sendmail.rb +232 -0
- data/lib/sisimai/mta/x1.rb +156 -0
- data/lib/sisimai/mta/x2.rb +157 -0
- data/lib/sisimai/mta/x3.rb +171 -0
- data/lib/sisimai/mta/x4.rb +365 -0
- data/lib/sisimai/mta/x5.rb +208 -0
- data/lib/sisimai/order.rb +217 -0
- data/lib/sisimai/reason.rb +235 -0
- data/lib/sisimai/reason/blocked.rb +105 -0
- data/lib/sisimai/reason/contenterror.rb +53 -0
- data/lib/sisimai/reason/exceedlimit.rb +60 -0
- data/lib/sisimai/reason/expired.rb +53 -0
- data/lib/sisimai/reason/filtered.rb +98 -0
- data/lib/sisimai/reason/hasmoved.rb +45 -0
- data/lib/sisimai/reason/hostunknown.rb +74 -0
- data/lib/sisimai/reason/mailboxfull.rb +118 -0
- data/lib/sisimai/reason/mailererror.rb +55 -0
- data/lib/sisimai/reason/mesgtoobig.rb +77 -0
- data/lib/sisimai/reason/networkerror.rb +57 -0
- data/lib/sisimai/reason/norelaying.rb +71 -0
- data/lib/sisimai/reason/notaccept.rb +63 -0
- data/lib/sisimai/reason/onhold.rb +45 -0
- data/lib/sisimai/reason/rejected.rb +101 -0
- data/lib/sisimai/reason/securityerror.rb +72 -0
- data/lib/sisimai/reason/spamdetected.rb +172 -0
- data/lib/sisimai/reason/suspend.rb +58 -0
- data/lib/sisimai/reason/systemerror.rb +69 -0
- data/lib/sisimai/reason/systemfull.rb +45 -0
- data/lib/sisimai/reason/toomanyconn.rb +73 -0
- data/lib/sisimai/reason/userunknown.rb +194 -0
- data/lib/sisimai/rfc2606.rb +24 -0
- data/lib/sisimai/rfc3464.rb +497 -0
- data/lib/sisimai/rfc3834.rb +150 -0
- data/lib/sisimai/rfc5322.rb +204 -0
- data/lib/sisimai/rhost.rb +47 -0
- data/lib/sisimai/rhost/googleapps.rb +237 -0
- data/lib/sisimai/smtp.rb +58 -0
- data/lib/sisimai/smtp/reply.rb +81 -0
- data/lib/sisimai/smtp/status.rb +755 -0
- data/lib/sisimai/string.rb +65 -0
- data/lib/sisimai/time.rb +11 -0
- data/lib/sisimai/version.rb +4 -0
- data/set-of-emails/README.md +35 -0
- data/set-of-emails/mailbox/mbox-0 +2467 -0
- data/set-of-emails/mailbox/mbox-1 +71 -0
- data/set-of-emails/maildir/bsd/README.md +261 -0
- data/set-of-emails/maildir/bsd/activehunter-01.eml +54 -0
- data/set-of-emails/maildir/bsd/activehunter-02.eml +53 -0
- data/set-of-emails/maildir/bsd/apachejames-01.eml +46 -0
- data/set-of-emails/maildir/bsd/arf-01.eml +66 -0
- data/set-of-emails/maildir/bsd/arf-02.eml +68 -0
- data/set-of-emails/maildir/bsd/arf-03.eml +56 -0
- data/set-of-emails/maildir/bsd/arf-04.eml +89 -0
- data/set-of-emails/maildir/bsd/arf-05.eml +82 -0
- data/set-of-emails/maildir/bsd/arf-06.eml +166 -0
- data/set-of-emails/maildir/bsd/arf-07.eml +59 -0
- data/set-of-emails/maildir/bsd/arf-08.eml +103 -0
- data/set-of-emails/maildir/bsd/arf-09.eml +104 -0
- data/set-of-emails/maildir/bsd/arf-10.eml +56 -0
- data/set-of-emails/maildir/bsd/arf-11.eml +37 -0
- data/set-of-emails/maildir/bsd/arf-12.eml +40 -0
- data/set-of-emails/maildir/bsd/arf-13.eml +76 -0
- data/set-of-emails/maildir/bsd/arf-14.eml +333 -0
- data/set-of-emails/maildir/bsd/arf-15.eml +66 -0
- data/set-of-emails/maildir/bsd/courier-01.eml +79 -0
- data/set-of-emails/maildir/bsd/courier-02.eml +83 -0
- data/set-of-emails/maildir/bsd/courier-03.eml +85 -0
- data/set-of-emails/maildir/bsd/courier-04.eml +87 -0
- data/set-of-emails/maildir/bsd/de-einsundeins-01.eml +38 -0
- data/set-of-emails/maildir/bsd/de-gmx-01.eml +52 -0
- data/set-of-emails/maildir/bsd/de-gmx-02.eml +51 -0
- data/set-of-emails/maildir/bsd/de-gmx-03.eml +56 -0
- data/set-of-emails/maildir/bsd/de-gmx-04.eml +51 -0
- data/set-of-emails/maildir/bsd/domino-01.eml +33 -0
- data/set-of-emails/maildir/bsd/domino-02.eml +83 -0
- data/set-of-emails/maildir/bsd/exchange-01.eml +31 -0
- data/set-of-emails/maildir/bsd/exchange-02.eml +67 -0
- data/set-of-emails/maildir/bsd/exchange-03.eml +52 -0
- data/set-of-emails/maildir/bsd/exchange-04.eml +28 -0
- data/set-of-emails/maildir/bsd/exchange-05.eml +56 -0
- data/set-of-emails/maildir/bsd/exchange-06.eml +151 -0
- data/set-of-emails/maildir/bsd/exim-01.eml +46 -0
- data/set-of-emails/maildir/bsd/exim-02.eml +41 -0
- data/set-of-emails/maildir/bsd/exim-03.eml +42 -0
- data/set-of-emails/maildir/bsd/exim-04.eml +46 -0
- data/set-of-emails/maildir/bsd/exim-05.eml +49 -0
- data/set-of-emails/maildir/bsd/exim-06.eml +44 -0
- data/set-of-emails/maildir/bsd/exim-07.eml +28 -0
- data/set-of-emails/maildir/bsd/exim-08.eml +42 -0
- data/set-of-emails/maildir/bsd/exim-09.eml +169 -0
- data/set-of-emails/maildir/bsd/exim-10.eml +718 -0
- data/set-of-emails/maildir/bsd/exim-11.eml +718 -0
- data/set-of-emails/maildir/bsd/exim-12.eml +75 -0
- data/set-of-emails/maildir/bsd/exim-13.eml +145 -0
- data/set-of-emails/maildir/bsd/exim-14.eml +32 -0
- data/set-of-emails/maildir/bsd/exim-15.eml +49 -0
- data/set-of-emails/maildir/bsd/exim-16.eml +98 -0
- data/set-of-emails/maildir/bsd/exim-17.eml +50 -0
- data/set-of-emails/maildir/bsd/exim-18.eml +96 -0
- data/set-of-emails/maildir/bsd/exim-19.eml +52 -0
- data/set-of-emails/maildir/bsd/exim-20.eml +159 -0
- data/set-of-emails/maildir/bsd/exim-21.eml +150 -0
- data/set-of-emails/maildir/bsd/exim-22.eml +50 -0
- data/set-of-emails/maildir/bsd/exim-23.eml +57 -0
- data/set-of-emails/maildir/bsd/exim-24.eml +107 -0
- data/set-of-emails/maildir/bsd/exim-25.eml +18 -0
- data/set-of-emails/maildir/bsd/exim-26.eml +111 -0
- data/set-of-emails/maildir/bsd/exim-27.eml +120 -0
- data/set-of-emails/maildir/bsd/exim-28.eml +148 -0
- data/set-of-emails/maildir/bsd/google-apps-01.eml +66 -0
- data/set-of-emails/maildir/bsd/imailserver-01.eml +27 -0
- data/set-of-emails/maildir/bsd/imailserver-02.eml +36 -0
- data/set-of-emails/maildir/bsd/imailserver-03.eml +28 -0
- data/set-of-emails/maildir/bsd/imailserver-04.eml +15 -0
- data/set-of-emails/maildir/bsd/imailserver-05.eml +92 -0
- data/set-of-emails/maildir/bsd/imailserver-06.eml +29 -0
- data/set-of-emails/maildir/bsd/interscanmss-01.eml +49 -0
- data/set-of-emails/maildir/bsd/interscanmss-02.eml +259 -0
- data/set-of-emails/maildir/bsd/jp-biglobe-01.eml +43 -0
- data/set-of-emails/maildir/bsd/jp-ezweb-01.eml +36 -0
- data/set-of-emails/maildir/bsd/jp-ezweb-02.eml +65 -0
- data/set-of-emails/maildir/bsd/jp-ezweb-03.eml +35 -0
- data/set-of-emails/maildir/bsd/jp-ezweb-04.eml +38 -0
- data/set-of-emails/maildir/bsd/jp-ezweb-05.eml +38 -0
- data/set-of-emails/maildir/bsd/jp-ezweb-06.eml +33 -0
- data/set-of-emails/maildir/bsd/jp-kddi-01.eml +49 -0
- data/set-of-emails/maildir/bsd/jp-kddi-02.eml +54 -0
- data/set-of-emails/maildir/bsd/jp-kddi-03.eml +54 -0
- data/set-of-emails/maildir/bsd/mailfoundry-01.eml +50 -0
- data/set-of-emails/maildir/bsd/mailfoundry-02.eml +49 -0
- data/set-of-emails/maildir/bsd/mailmarshalsmtp-01.eml +43 -0
- data/set-of-emails/maildir/bsd/mcafee-01.eml +63 -0
- data/set-of-emails/maildir/bsd/mcafee-02.eml +65 -0
- data/set-of-emails/maildir/bsd/mcafee-03.eml +59 -0
- data/set-of-emails/maildir/bsd/messagingserver-01.eml +102 -0
- data/set-of-emails/maildir/bsd/messagingserver-02.eml +72 -0
- data/set-of-emails/maildir/bsd/messagingserver-03.eml +70 -0
- data/set-of-emails/maildir/bsd/messagingserver-04.eml +102 -0
- data/set-of-emails/maildir/bsd/messagingserver-05.eml +98 -0
- data/set-of-emails/maildir/bsd/messagingserver-06.eml +101 -0
- data/set-of-emails/maildir/bsd/messagingserver-07.eml +129 -0
- data/set-of-emails/maildir/bsd/mfilter-01.eml +49 -0
- data/set-of-emails/maildir/bsd/mfilter-02.eml +48 -0
- data/set-of-emails/maildir/bsd/mfilter-03.eml +43 -0
- data/set-of-emails/maildir/bsd/mxlogic-01.eml +47 -0
- data/set-of-emails/maildir/bsd/mxlogic-02.eml +44 -0
- data/set-of-emails/maildir/bsd/mxlogic-03.eml +46 -0
- data/set-of-emails/maildir/bsd/notes-01.eml +42 -0
- data/set-of-emails/maildir/bsd/notes-02.eml +42 -0
- data/set-of-emails/maildir/bsd/notes-03.eml +38 -0
- data/set-of-emails/maildir/bsd/notes-04.eml +181 -0
- data/set-of-emails/maildir/bsd/opensmtpd-01.eml +33 -0
- data/set-of-emails/maildir/bsd/opensmtpd-02.eml +33 -0
- data/set-of-emails/maildir/bsd/opensmtpd-03.eml +36 -0
- data/set-of-emails/maildir/bsd/opensmtpd-04.eml +40 -0
- data/set-of-emails/maildir/bsd/opensmtpd-05.eml +36 -0
- data/set-of-emails/maildir/bsd/postfix-01.eml +60 -0
- data/set-of-emails/maildir/bsd/postfix-02.eml +78 -0
- data/set-of-emails/maildir/bsd/postfix-03.eml +71 -0
- data/set-of-emails/maildir/bsd/postfix-04.eml +89 -0
- data/set-of-emails/maildir/bsd/postfix-05.eml +78 -0
- data/set-of-emails/maildir/bsd/postfix-06.eml +72 -0
- data/set-of-emails/maildir/bsd/postfix-07.eml +74 -0
- data/set-of-emails/maildir/bsd/postfix-08.eml +78 -0
- data/set-of-emails/maildir/bsd/postfix-09.eml +76 -0
- data/set-of-emails/maildir/bsd/postfix-10.eml +73 -0
- data/set-of-emails/maildir/bsd/postfix-11.eml +86 -0
- data/set-of-emails/maildir/bsd/postfix-12.eml +71 -0
- data/set-of-emails/maildir/bsd/postfix-13.eml +81 -0
- data/set-of-emails/maildir/bsd/postfix-14.eml +68 -0
- data/set-of-emails/maildir/bsd/postfix-15.eml +69 -0
- data/set-of-emails/maildir/bsd/postfix-16.eml +73 -0
- data/set-of-emails/maildir/bsd/postfix-17.eml +68 -0
- data/set-of-emails/maildir/bsd/postfix-18.eml +121 -0
- data/set-of-emails/maildir/bsd/postfix-19.eml +105 -0
- data/set-of-emails/maildir/bsd/postfix-20.eml +231 -0
- data/set-of-emails/maildir/bsd/postfix-21.eml +60 -0
- data/set-of-emails/maildir/bsd/qmail-01.eml +40 -0
- data/set-of-emails/maildir/bsd/qmail-02.eml +35 -0
- data/set-of-emails/maildir/bsd/qmail-03.eml +22 -0
- data/set-of-emails/maildir/bsd/qmail-04.eml +31 -0
- data/set-of-emails/maildir/bsd/qmail-05.eml +31 -0
- data/set-of-emails/maildir/bsd/qmail-06.eml +39 -0
- data/set-of-emails/maildir/bsd/qmail-07.eml +22 -0
- data/set-of-emails/maildir/bsd/qmail-08.eml +23 -0
- data/set-of-emails/maildir/bsd/qmail-09.eml +103 -0
- data/set-of-emails/maildir/bsd/rfc3464-01.eml +60 -0
- data/set-of-emails/maildir/bsd/rfc3464-02.eml +43 -0
- data/set-of-emails/maildir/bsd/rfc3464-03.eml +40 -0
- data/set-of-emails/maildir/bsd/rfc3464-04.eml +50 -0
- data/set-of-emails/maildir/bsd/rfc3464-05.eml +63 -0
- data/set-of-emails/maildir/bsd/rfc3464-06.eml +48 -0
- data/set-of-emails/maildir/bsd/rfc3464-07.eml +88 -0
- data/set-of-emails/maildir/bsd/rfc3464-08.eml +70 -0
- data/set-of-emails/maildir/bsd/rfc3464-09.eml +93 -0
- data/set-of-emails/maildir/bsd/rfc3464-10.eml +467 -0
- data/set-of-emails/maildir/bsd/rfc3464-11.eml +1171 -0
- data/set-of-emails/maildir/bsd/rfc3464-12.eml +101 -0
- data/set-of-emails/maildir/bsd/rfc3464-13.eml +131 -0
- data/set-of-emails/maildir/bsd/rfc3464-14.eml +121 -0
- data/set-of-emails/maildir/bsd/rfc3464-15.eml +144 -0
- data/set-of-emails/maildir/bsd/rfc3464-16.eml +36 -0
- data/set-of-emails/maildir/bsd/rfc3464-17.eml +109 -0
- data/set-of-emails/maildir/bsd/rfc3464-18.eml +149 -0
- data/set-of-emails/maildir/bsd/rfc3464-19.eml +65 -0
- data/set-of-emails/maildir/bsd/rfc3464-20.eml +145 -0
- data/set-of-emails/maildir/bsd/rfc3464-21.eml +146 -0
- data/set-of-emails/maildir/bsd/rfc3464-22.eml +105 -0
- data/set-of-emails/maildir/bsd/rfc3464-23.eml +21 -0
- data/set-of-emails/maildir/bsd/rfc3464-24.eml +27 -0
- data/set-of-emails/maildir/bsd/rfc3464-25.eml +33 -0
- data/set-of-emails/maildir/bsd/rfc3464-26.eml +98 -0
- data/set-of-emails/maildir/bsd/rfc3464-27.eml +180 -0
- data/set-of-emails/maildir/bsd/rfc3834-01.eml +37 -0
- data/set-of-emails/maildir/bsd/rfc3834-02.eml +51 -0
- data/set-of-emails/maildir/bsd/rfc3834-03.eml +33 -0
- data/set-of-emails/maildir/bsd/ru-mailru-01.eml +54 -0
- data/set-of-emails/maildir/bsd/ru-mailru-02.eml +54 -0
- data/set-of-emails/maildir/bsd/ru-mailru-03.eml +62 -0
- data/set-of-emails/maildir/bsd/ru-mailru-04.eml +54 -0
- data/set-of-emails/maildir/bsd/ru-yandex-01.eml +102 -0
- data/set-of-emails/maildir/bsd/ru-yandex-02.eml +113 -0
- data/set-of-emails/maildir/bsd/ru-yandex-03.eml +101 -0
- data/set-of-emails/maildir/bsd/sendmail-01.eml +70 -0
- data/set-of-emails/maildir/bsd/sendmail-02.eml +82 -0
- data/set-of-emails/maildir/bsd/sendmail-03.eml +76 -0
- data/set-of-emails/maildir/bsd/sendmail-04.eml +63 -0
- data/set-of-emails/maildir/bsd/sendmail-05.eml +64 -0
- data/set-of-emails/maildir/bsd/sendmail-06.eml +67 -0
- data/set-of-emails/maildir/bsd/sendmail-07.eml +65 -0
- data/set-of-emails/maildir/bsd/sendmail-08.eml +62 -0
- data/set-of-emails/maildir/bsd/sendmail-09.eml +60 -0
- data/set-of-emails/maildir/bsd/sendmail-10.eml +82 -0
- data/set-of-emails/maildir/bsd/sendmail-11.eml +60 -0
- data/set-of-emails/maildir/bsd/sendmail-12.eml +62 -0
- data/set-of-emails/maildir/bsd/sendmail-13.eml +66 -0
- data/set-of-emails/maildir/bsd/sendmail-14.eml +64 -0
- data/set-of-emails/maildir/bsd/sendmail-15.eml +60 -0
- data/set-of-emails/maildir/bsd/sendmail-16.eml +69 -0
- data/set-of-emails/maildir/bsd/sendmail-17.eml +68 -0
- data/set-of-emails/maildir/bsd/sendmail-18.eml +64 -0
- data/set-of-emails/maildir/bsd/sendmail-19.eml +71 -0
- data/set-of-emails/maildir/bsd/sendmail-20.eml +120 -0
- data/set-of-emails/maildir/bsd/sendmail-21.eml +69 -0
- data/set-of-emails/maildir/bsd/sendmail-22.eml +73 -0
- data/set-of-emails/maildir/bsd/sendmail-23.eml +137 -0
- data/set-of-emails/maildir/bsd/sendmail-24.eml +66 -0
- data/set-of-emails/maildir/bsd/sendmail-25.eml +70 -0
- data/set-of-emails/maildir/bsd/sendmail-26.eml +71 -0
- data/set-of-emails/maildir/bsd/sendmail-27.eml +69 -0
- data/set-of-emails/maildir/bsd/sendmail-28.eml +69 -0
- data/set-of-emails/maildir/bsd/sendmail-29.eml +70 -0
- data/set-of-emails/maildir/bsd/sendmail-30.eml +68 -0
- data/set-of-emails/maildir/bsd/sendmail-31.eml +80 -0
- data/set-of-emails/maildir/bsd/sendmail-32.eml +71 -0
- data/set-of-emails/maildir/bsd/sendmail-33.eml +71 -0
- data/set-of-emails/maildir/bsd/sendmail-34.eml +75 -0
- data/set-of-emails/maildir/bsd/sendmail-35.eml +70 -0
- data/set-of-emails/maildir/bsd/sendmail-36.eml +71 -0
- data/set-of-emails/maildir/bsd/sendmail-37.eml +71 -0
- data/set-of-emails/maildir/bsd/surfcontrol-01.eml +79 -0
- data/set-of-emails/maildir/bsd/surfcontrol-02.eml +70 -0
- data/set-of-emails/maildir/bsd/surfcontrol-03.eml +70 -0
- data/set-of-emails/maildir/bsd/uk-messagelabs-01.eml +76 -0
- data/set-of-emails/maildir/bsd/us-amazonses-01.eml +59 -0
- data/set-of-emails/maildir/bsd/us-amazonses-02.eml +177 -0
- data/set-of-emails/maildir/bsd/us-amazonses-03.eml +55 -0
- data/set-of-emails/maildir/bsd/us-amazonses-04.eml +55 -0
- data/set-of-emails/maildir/bsd/us-aol-01.eml +1258 -0
- data/set-of-emails/maildir/bsd/us-aol-02.eml +1257 -0
- data/set-of-emails/maildir/bsd/us-aol-03.eml +1264 -0
- data/set-of-emails/maildir/bsd/us-aol-04.eml +1260 -0
- data/set-of-emails/maildir/bsd/us-bigfoot-01.eml +64 -0
- data/set-of-emails/maildir/bsd/us-facebook-01.eml +40 -0
- data/set-of-emails/maildir/bsd/us-facebook-02.eml +42 -0
- data/set-of-emails/maildir/bsd/us-google-01.eml +70 -0
- data/set-of-emails/maildir/bsd/us-google-02.eml +50 -0
- data/set-of-emails/maildir/bsd/us-google-03.eml +51 -0
- data/set-of-emails/maildir/bsd/us-google-04.eml +82 -0
- data/set-of-emails/maildir/bsd/us-google-05.eml +50 -0
- data/set-of-emails/maildir/bsd/us-google-06.eml +56 -0
- data/set-of-emails/maildir/bsd/us-google-07.eml +42 -0
- data/set-of-emails/maildir/bsd/us-google-08.eml +59 -0
- data/set-of-emails/maildir/bsd/us-google-09.eml +76 -0
- data/set-of-emails/maildir/bsd/us-google-10.eml +69 -0
- data/set-of-emails/maildir/bsd/us-google-11.eml +68 -0
- data/set-of-emails/maildir/bsd/us-google-12.eml +76 -0
- data/set-of-emails/maildir/bsd/us-google-13.eml +79 -0
- data/set-of-emails/maildir/bsd/us-google-14.eml +304 -0
- data/set-of-emails/maildir/bsd/us-outlook-01.eml +72 -0
- data/set-of-emails/maildir/bsd/us-outlook-02.eml +72 -0
- data/set-of-emails/maildir/bsd/us-outlook-03.eml +72 -0
- data/set-of-emails/maildir/bsd/us-outlook-04.eml +79 -0
- data/set-of-emails/maildir/bsd/us-outlook-05.eml +85 -0
- data/set-of-emails/maildir/bsd/us-outlook-06.eml +75 -0
- data/set-of-emails/maildir/bsd/us-outlook-07.eml +70 -0
- data/set-of-emails/maildir/bsd/us-receivingses-01.eml +74 -0
- data/set-of-emails/maildir/bsd/us-receivingses-02.eml +74 -0
- data/set-of-emails/maildir/bsd/us-receivingses-03.eml +74 -0
- data/set-of-emails/maildir/bsd/us-receivingses-04.eml +74 -0
- data/set-of-emails/maildir/bsd/us-receivingses-05.eml +74 -0
- data/set-of-emails/maildir/bsd/us-receivingses-06.eml +74 -0
- data/set-of-emails/maildir/bsd/us-receivingses-07.eml +74 -0
- data/set-of-emails/maildir/bsd/us-sendgrid-01.eml +95 -0
- data/set-of-emails/maildir/bsd/us-sendgrid-02.eml +98 -0
- data/set-of-emails/maildir/bsd/us-sendgrid-03.eml +100 -0
- data/set-of-emails/maildir/bsd/us-verizon-01.eml +31 -0
- data/set-of-emails/maildir/bsd/us-yahoo-01.eml +78 -0
- data/set-of-emails/maildir/bsd/us-yahoo-02.eml +79 -0
- data/set-of-emails/maildir/bsd/us-yahoo-03.eml +93 -0
- data/set-of-emails/maildir/bsd/us-yahoo-04.eml +94 -0
- data/set-of-emails/maildir/bsd/us-yahoo-05.eml +94 -0
- data/set-of-emails/maildir/bsd/us-zoho-01.eml +40 -0
- data/set-of-emails/maildir/bsd/us-zoho-02.eml +38 -0
- data/set-of-emails/maildir/bsd/us-zoho-03.eml +37 -0
- data/set-of-emails/maildir/bsd/us-zoho-04.eml +47 -0
- data/set-of-emails/maildir/bsd/us-zoho-05.eml +37 -0
- data/set-of-emails/maildir/bsd/v5sendmail-01.eml +24 -0
- data/set-of-emails/maildir/bsd/v5sendmail-02.eml +26 -0
- data/set-of-emails/maildir/bsd/v5sendmail-03.eml +29 -0
- data/set-of-emails/maildir/bsd/v5sendmail-04.eml +29 -0
- data/set-of-emails/maildir/bsd/v5sendmail-05.eml +42 -0
- data/set-of-emails/maildir/bsd/v5sendmail-06.eml +28 -0
- data/set-of-emails/maildir/bsd/v5sendmail-07.eml +35 -0
- data/set-of-emails/maildir/bsd/x1-01.eml +61 -0
- data/set-of-emails/maildir/bsd/x1-02.eml +62 -0
- data/set-of-emails/maildir/bsd/x2-01.eml +41 -0
- data/set-of-emails/maildir/bsd/x2-02.eml +46 -0
- data/set-of-emails/maildir/bsd/x2-03.eml +34 -0
- data/set-of-emails/maildir/bsd/x2-04.eml +0 -0
- data/set-of-emails/maildir/bsd/x2-05.eml +98 -0
- data/set-of-emails/maildir/bsd/x3-01.eml +61 -0
- data/set-of-emails/maildir/bsd/x3-02.eml +64 -0
- data/set-of-emails/maildir/bsd/x3-03.eml +59 -0
- data/set-of-emails/maildir/bsd/x3-04.eml +106 -0
- data/set-of-emails/maildir/bsd/x4-01.eml +92 -0
- data/set-of-emails/maildir/bsd/x4-02.eml +112 -0
- data/set-of-emails/maildir/bsd/x4-03.eml +245 -0
- data/set-of-emails/maildir/bsd/x4-04.eml +81 -0
- data/set-of-emails/maildir/bsd/x4-05.eml +121 -0
- data/set-of-emails/maildir/bsd/x4-06.eml +32 -0
- data/set-of-emails/maildir/bsd/x4-07.eml +153 -0
- data/set-of-emails/maildir/bsd/x5-01.eml +155 -0
- data/set-of-emails/maildir/dos/activehunter-01.eml +54 -0
- data/set-of-emails/maildir/dos/apachejames-01.eml +46 -0
- data/set-of-emails/maildir/dos/arf-01.eml +66 -0
- data/set-of-emails/maildir/dos/courier-01.eml +79 -0
- data/set-of-emails/maildir/dos/de-einsundeins-01.eml +38 -0
- data/set-of-emails/maildir/dos/de-gmx-01.eml +52 -0
- data/set-of-emails/maildir/dos/domino-01.eml +33 -0
- data/set-of-emails/maildir/dos/exchange-01.eml +31 -0
- data/set-of-emails/maildir/dos/exim-01.eml +46 -0
- data/set-of-emails/maildir/dos/google-apps-01.eml +66 -0
- data/set-of-emails/maildir/dos/imailserver-01.eml +27 -0
- data/set-of-emails/maildir/dos/interscanmss-01.eml +49 -0
- data/set-of-emails/maildir/dos/jp-biglobe-01.eml +43 -0
- data/set-of-emails/maildir/dos/jp-ezweb-01.eml +36 -0
- data/set-of-emails/maildir/dos/jp-kddi-01.eml +49 -0
- data/set-of-emails/maildir/dos/mailfoundry-01.eml +50 -0
- data/set-of-emails/maildir/dos/mailmarshalsmtp-01.eml +43 -0
- data/set-of-emails/maildir/dos/mcafee-01.eml +63 -0
- data/set-of-emails/maildir/dos/messagingserver-01.eml +102 -0
- data/set-of-emails/maildir/dos/mfilter-01.eml +49 -0
- data/set-of-emails/maildir/dos/mxlogic-01.eml +47 -0
- data/set-of-emails/maildir/dos/notes-01.eml +42 -0
- data/set-of-emails/maildir/dos/opensmtpd-01.eml +33 -0
- data/set-of-emails/maildir/dos/postfix-01.eml +60 -0
- data/set-of-emails/maildir/dos/qmail-01.eml +40 -0
- data/set-of-emails/maildir/dos/rfc3464-01.eml +59 -0
- data/set-of-emails/maildir/dos/rfc3834-01.eml +37 -0
- data/set-of-emails/maildir/dos/ru-mailru-01.eml +54 -0
- data/set-of-emails/maildir/dos/ru-yandex-01.eml +102 -0
- data/set-of-emails/maildir/dos/sendmail-01.eml +69 -0
- data/set-of-emails/maildir/dos/surfcontrol-01.eml +79 -0
- data/set-of-emails/maildir/dos/uk-messagelabs-01.eml +76 -0
- data/set-of-emails/maildir/dos/us-amazonses-01.eml +59 -0
- data/set-of-emails/maildir/dos/us-aol-01.eml +1258 -0
- data/set-of-emails/maildir/dos/us-bigfoot-01.eml +64 -0
- data/set-of-emails/maildir/dos/us-facebook-01.eml +40 -0
- data/set-of-emails/maildir/dos/us-google-01.eml +70 -0
- data/set-of-emails/maildir/dos/us-outlook-01.eml +72 -0
- data/set-of-emails/maildir/dos/us-receivingses-01.eml +74 -0
- data/set-of-emails/maildir/dos/us-sendgrid-01.eml +95 -0
- data/set-of-emails/maildir/dos/us-verizon-01.eml +31 -0
- data/set-of-emails/maildir/dos/us-yahoo-01.eml +78 -0
- data/set-of-emails/maildir/dos/us-zoho-01.eml +40 -0
- data/set-of-emails/maildir/dos/v5sendmail-01.eml +24 -0
- data/set-of-emails/maildir/dos/x1-01.eml +61 -0
- data/set-of-emails/maildir/dos/x2-01.eml +41 -0
- data/set-of-emails/maildir/dos/x3-01.eml +61 -0
- data/set-of-emails/maildir/dos/x4-01.eml +90 -0
- data/set-of-emails/maildir/dos/x5-01.eml +155 -0
- data/set-of-emails/maildir/err/make-test-01.eml +70 -0
- data/set-of-emails/maildir/err/make-test-02.eml +70 -0
- data/set-of-emails/maildir/err/make-test-03.eml +64 -0
- data/set-of-emails/maildir/err/make-test-04.eml +64 -0
- data/set-of-emails/maildir/err/make-test-05.eml +66 -0
- data/set-of-emails/maildir/err/make-test-06.eml +118 -0
- data/set-of-emails/maildir/err/make-test-07.eml +26 -0
- data/set-of-emails/maildir/err/make-test-08.eml +67 -0
- data/set-of-emails/maildir/err/make-test-09.eml +55 -0
- data/set-of-emails/maildir/err/make-test-10.eml +69 -0
- data/set-of-emails/maildir/err/make-test-11.eml +64 -0
- data/set-of-emails/maildir/err/make-test-12.eml +66 -0
- data/set-of-emails/maildir/err/make-test-13.eml +67 -0
- data/set-of-emails/maildir/err/make-test-14.eml +66 -0
- data/set-of-emails/maildir/err/make-test-15.eml +70 -0
- data/set-of-emails/maildir/err/make-test-16.eml +68 -0
- data/set-of-emails/maildir/err/make-test-17.eml +68 -0
- data/set-of-emails/maildir/err/make-test-18.eml +68 -0
- data/set-of-emails/maildir/err/make-test-19.eml +69 -0
- data/set-of-emails/maildir/err/make-test-20.eml +67 -0
- data/set-of-emails/maildir/err/make-test-21.eml +69 -0
- data/set-of-emails/maildir/err/make-test-22.eml +66 -0
- data/set-of-emails/maildir/err/make-test-23.eml +70 -0
- data/set-of-emails/maildir/err/make-test-24.eml +69 -0
- data/set-of-emails/maildir/err/make-test-25.eml +67 -0
- data/set-of-emails/maildir/err/make-test-26.eml +69 -0
- data/set-of-emails/maildir/err/make-test-27.eml +69 -0
- data/set-of-emails/maildir/err/make-test-28.eml +66 -0
- data/set-of-emails/maildir/err/make-test-29.eml +68 -0
- data/set-of-emails/maildir/err/make-test-30.eml +68 -0
- data/set-of-emails/maildir/err/make-test-31.eml +80 -0
- data/set-of-emails/maildir/err/make-test-32.eml +66 -0
- data/set-of-emails/maildir/err/make-test-33.eml +68 -0
- data/set-of-emails/maildir/err/make-test-34.eml +56 -0
- data/set-of-emails/maildir/err/make-test-35.eml +59 -0
- data/set-of-emails/maildir/err/make-test-36.eml +53 -0
- data/set-of-emails/maildir/err/make-test-37.eml +62 -0
- data/set-of-emails/maildir/mac/activehunter-01.eml +1 -2
- data/set-of-emails/maildir/mac/apachejames-01.eml +1 -4
- data/set-of-emails/maildir/mac/arf-01.eml +1 -3
- data/set-of-emails/maildir/mac/courier-01.eml +1 -6
- data/set-of-emails/maildir/mac/de-einsundeins-01.eml +1 -1
- data/set-of-emails/maildir/mac/de-gmx-01.eml +1 -1
- data/set-of-emails/maildir/mac/domino-01.eml +1 -0
- data/set-of-emails/maildir/mac/exchange-01.eml +1 -0
- data/set-of-emails/maildir/mac/exim-01.eml +1 -1
- data/set-of-emails/maildir/mac/google-apps-01.eml +1 -4
- data/set-of-emails/maildir/mac/imailserver-01.eml +1 -0
- data/set-of-emails/maildir/mac/interscanmss-01.eml +1 -2
- data/set-of-emails/maildir/mac/jp-biglobe-01.eml +1 -2
- data/set-of-emails/maildir/mac/jp-ezweb-01.eml +1 -1
- data/set-of-emails/maildir/mac/jp-kddi-01.eml +1 -2
- data/set-of-emails/maildir/mac/mailfoundry-01.eml +1 -2
- data/set-of-emails/maildir/mac/mailmarshalsmtp-01.eml +1 -2
- data/set-of-emails/maildir/mac/mcafee-01.eml +1 -4
- data/set-of-emails/maildir/mac/messagingserver-01.eml +1 -4
- data/set-of-emails/maildir/mac/mfilter-01.eml +1 -3
- data/set-of-emails/maildir/mac/mxlogic-01.eml +1 -1
- data/set-of-emails/maildir/mac/notes-01.eml +1 -2
- data/set-of-emails/maildir/mac/opensmtpd-01.eml +1 -0
- data/set-of-emails/maildir/mac/postfix-01.eml +1 -3
- data/set-of-emails/maildir/mac/qmail-01.eml +1 -1
- data/set-of-emails/maildir/mac/rfc3464-01.eml +1 -4
- data/set-of-emails/maildir/mac/rfc3834-01.eml +1 -0
- data/set-of-emails/maildir/mac/ru-mailru-01.eml +1 -1
- data/set-of-emails/maildir/mac/ru-yandex-01.eml +1 -4
- data/set-of-emails/maildir/mac/sendmail-01.eml +1 -4
- data/set-of-emails/maildir/mac/surfcontrol-01.eml +1 -5
- data/set-of-emails/maildir/mac/uk-messagelabs-01.eml +1 -4
- data/set-of-emails/maildir/mac/us-amazonses-01.eml +1 -4
- data/set-of-emails/maildir/mac/us-aol-01.eml +1 -15
- data/set-of-emails/maildir/mac/us-bigfoot-01.eml +1 -4
- data/set-of-emails/maildir/mac/us-facebook-01.eml +1 -4
- data/set-of-emails/maildir/mac/us-google-01.eml +1 -1
- data/set-of-emails/maildir/mac/us-outlook-01.eml +1 -4
- data/set-of-emails/maildir/mac/us-receivingses-01.eml +1 -4
- data/set-of-emails/maildir/mac/us-sendgrid-01.eml +1 -3
- data/set-of-emails/maildir/mac/us-verizon-01.eml +1 -2
- data/set-of-emails/maildir/mac/us-yahoo-01.eml +1 -1
- data/set-of-emails/maildir/mac/us-zoho-01.eml +1 -2
- data/set-of-emails/maildir/mac/v5sendmail-01.eml +1 -0
- data/set-of-emails/maildir/mac/x1-01.eml +1 -4
- data/set-of-emails/maildir/mac/x2-01.eml +1 -1
- data/set-of-emails/maildir/mac/x3-01.eml +1 -3
- data/set-of-emails/maildir/mac/x4-01.eml +1 -2
- data/set-of-emails/maildir/mac/x5-01.eml +1 -8
- data/set-of-emails/maildir/not/is-not-bounce-01.eml +25 -0
- data/set-of-emails/to-be-debugged-because/reason-is-onhold/onhold-0001.eml +85 -0
- data/set-of-emails/to-be-debugged-because/reason-is-undefined/undefined-0002.eml +27 -0
- data/set-of-emails/to-be-debugged-because/reason-is-undefined/undefined-0003.eml +78 -0
- data/set-of-emails/to-be-debugged-because/sisimai-cannot-parse-yet/cannot-parse-this-email-0002.eml +25 -0
- data/set-of-emails/to-be-debugged-because/something-is-wrong/issue-106-01.eml +79 -0
- data/set-of-emails/to-be-debugged-because/something-is-wrong/issue-106-02.eml +72 -0
- data/set-of-emails/to-be-debugged-because/something-is-wrong/issue-106-03.eml +68 -0
- data/set-of-emails/to-be-debugged-because/something-is-wrong/no-message-id-from-pr-150.eml +75 -0
- data/set-of-emails/to-be-parsed-for-test/README.md +20 -0
- data/sisimai.gemspec +25 -0
- metadata +647 -0
data/lib/sisimai/mail.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module Sisimai
|
2
|
+
# Sisimai::Mail is a handler of UNIX mbox or Maildir for reading each mail. It is
|
3
|
+
# wrapper class of Sisimai::Mail::Mbox and Sisimai::Mail::Maildir classes.
|
4
|
+
class Mail
|
5
|
+
# Imported from p5-Sisimail/lib/Sisimai/Mail.pm
|
6
|
+
@@roaccessors = [
|
7
|
+
:path, # [String] path to mbox or Maildir/
|
8
|
+
:type, # [String] Data type: mailbox, maildir, or stdin
|
9
|
+
]
|
10
|
+
@@rwaccessors = [
|
11
|
+
:mail, # [Sisimai::Mail::Mbox, Sisimai::Mail::Maildir] Object
|
12
|
+
]
|
13
|
+
@@roaccessors.each { |e| attr_reader e }
|
14
|
+
@@rwaccessors.each { |e| attr_accessor e }
|
15
|
+
|
16
|
+
# Constructor of Sisimai::Mail
|
17
|
+
# @param [String] argv1 Path to mbox or Maildir/
|
18
|
+
# @return [Sisimai::Mail, Nil] Object or Undef if the argument was wrong
|
19
|
+
def initialize(argv1)
|
20
|
+
classname = nil
|
21
|
+
parameter = { 'path' => argv1, 'type' => nil, 'mail' => nil }
|
22
|
+
|
23
|
+
if argv1.is_a?(::String)
|
24
|
+
# Path to mail or '<STDIN>' ?
|
25
|
+
if argv1 == '<STDIN>'
|
26
|
+
# Sisimai::Mail.new('<STDIN>')
|
27
|
+
classname = sprintf('%s::STDIN', self.class)
|
28
|
+
parameter['type'] = 'stdin'
|
29
|
+
parameter['path'] = $stdin
|
30
|
+
|
31
|
+
else
|
32
|
+
# The argumenet is a mailbox or a Maildir/.
|
33
|
+
mediatype = File.ftype(argv1)
|
34
|
+
|
35
|
+
if mediatype == 'file'
|
36
|
+
# The argument is a file, it is an mbox or email file in Maildir/
|
37
|
+
classname = sprintf('%s::Mbox', self.class)
|
38
|
+
parameter['type'] = 'mailbox'
|
39
|
+
|
40
|
+
elsif mediatype == 'directory'
|
41
|
+
# The agument is not a file, it is a Maildir/
|
42
|
+
classname = sprintf('%s::Maildir', self.class)
|
43
|
+
parameter['type'] = 'maildir'
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
elsif argv1.is_a?(IO)
|
48
|
+
# Read from STDIN
|
49
|
+
# The argument neither a mailbox nor a Maildir/.
|
50
|
+
classname = sprintf('%s::STDIN', self.class)
|
51
|
+
parameter['type'] = 'stdin'
|
52
|
+
|
53
|
+
end
|
54
|
+
|
55
|
+
return nil unless classname
|
56
|
+
|
57
|
+
classpath = classname.gsub('::', '/').downcase
|
58
|
+
require classpath
|
59
|
+
parameter['mail'] = Module.const_get(classname).new(parameter['path'])
|
60
|
+
|
61
|
+
@path = parameter['path']
|
62
|
+
@type = parameter['type']
|
63
|
+
@mail = parameter['mail']
|
64
|
+
end
|
65
|
+
|
66
|
+
# Mbox/Maildir reader, works as an iterator.
|
67
|
+
# @return [String] Contents of mbox/Maildir
|
68
|
+
def read
|
69
|
+
return nil unless mail
|
70
|
+
return mail.read
|
71
|
+
end
|
72
|
+
|
73
|
+
# Close the handle
|
74
|
+
# @return [True,False] true: Successfully closed the handle
|
75
|
+
# false: Mail handle is not defined
|
76
|
+
def close
|
77
|
+
return false unless mail.handle
|
78
|
+
mail.handle = nil
|
79
|
+
return true
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Sisimai
|
2
|
+
class Mail
|
3
|
+
# Sisimai::Mail::Maildir is a reader for getting contents of each email in the
|
4
|
+
# Maildir/ directory.
|
5
|
+
class Maildir
|
6
|
+
# Imported from p5-Sisimail/lib/Sisimai/Mail/Maildir.pm
|
7
|
+
@@roaccessors = [
|
8
|
+
:dir, # [String] Path to Maildir/
|
9
|
+
:size, # [Integer] The number of entires in the directory
|
10
|
+
]
|
11
|
+
@@rwaccessors = [
|
12
|
+
:path, # [String] Path to each file
|
13
|
+
:file, # [String] Each file name of a mail in the Maildir/
|
14
|
+
:inodes, # [Array] i-node List of files in the Maildir/
|
15
|
+
:offset, # [Integer] Offset position for seeking
|
16
|
+
:handle, # [IO::Dir] Directory handle
|
17
|
+
]
|
18
|
+
@@roaccessors.each { |e| attr_reader e }
|
19
|
+
@@rwaccessors.each { |e| attr_accessor e }
|
20
|
+
|
21
|
+
# Constructor of Sisimai::Mail::Maildir
|
22
|
+
# @param [String] argvs Path to Maildir/
|
23
|
+
# @return [Sisimai::Mail::Maildir,Nil] Object or nil if the argument is
|
24
|
+
# not a directory or does not exist
|
25
|
+
def initialize(argv1)
|
26
|
+
raise Errno::ENOENT unless File.exist?(argv1)
|
27
|
+
raise Errno::ENOTDIR unless File.ftype(argv1) == 'directory'
|
28
|
+
|
29
|
+
@path = nil
|
30
|
+
@size = Dir.entries(argv1).size
|
31
|
+
@dir = argv1
|
32
|
+
@file = nil
|
33
|
+
@offset = 0
|
34
|
+
@inodes = {}
|
35
|
+
@handle = Dir.open(argv1)
|
36
|
+
end
|
37
|
+
|
38
|
+
# Maildir reader, works as a iterator.
|
39
|
+
# @return [String] Contents of file in Maildir/
|
40
|
+
def read
|
41
|
+
return nil unless self.offset < self.size
|
42
|
+
|
43
|
+
seekhandle = self.handle
|
44
|
+
filehandle = nil
|
45
|
+
readbuffer = ''
|
46
|
+
emailindir = ''
|
47
|
+
emailinode = nil
|
48
|
+
|
49
|
+
begin
|
50
|
+
while r = seekhandle.read do
|
51
|
+
# Read each file in the directory
|
52
|
+
self.offset = seekhandle.pos
|
53
|
+
next if r == '.' || r == '..'
|
54
|
+
|
55
|
+
emailindir = sprintf('%s/%s', self.dir, r)
|
56
|
+
emailindir = emailindir.squeeze('/')
|
57
|
+
|
58
|
+
next unless File.ftype(emailindir) == 'file'
|
59
|
+
next unless File.size(emailindir) > 0
|
60
|
+
next unless File.readable?(emailindir)
|
61
|
+
|
62
|
+
emailinode = File.stat(emailindir).ino
|
63
|
+
next if self.inodes.key?(emailinode)
|
64
|
+
|
65
|
+
filehandle = File.open(emailindir, 'r')
|
66
|
+
readbuffer = filehandle.read
|
67
|
+
filehandle.close
|
68
|
+
|
69
|
+
self.inodes[emailinode] = 1
|
70
|
+
self.path = emailindir
|
71
|
+
self.file = r
|
72
|
+
|
73
|
+
break
|
74
|
+
end
|
75
|
+
|
76
|
+
seekhandle.close unless self.offset < self.size
|
77
|
+
end
|
78
|
+
|
79
|
+
return readbuffer
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Sisimai
|
2
|
+
# Sisimai::Mail::Mbox is a mailbox file (UNIX mbox) reader.
|
3
|
+
class Mail
|
4
|
+
class Mbox
|
5
|
+
# Imported from p5-Sisimail/lib/Sisimai/Mail/Mbox.pm
|
6
|
+
@@roaccessors = [
|
7
|
+
:dir, # [String] Directory name of the mbox
|
8
|
+
:file, # [String] File name of the mbox
|
9
|
+
:path, # [String] Path to mbox
|
10
|
+
:size, # [Integer] File size of the mbox
|
11
|
+
]
|
12
|
+
@@rwaccessors = [
|
13
|
+
:offset, # [Integer] Offset position for seeking
|
14
|
+
:handle, # [IO::File] File handle
|
15
|
+
]
|
16
|
+
@@roaccessors.each { |e| attr_reader e }
|
17
|
+
@@rwaccessors.each { |e| attr_accessor e }
|
18
|
+
|
19
|
+
# Constructor of Sisimai::Mail::Mbox
|
20
|
+
# @param [String] argv1 Path to mbox
|
21
|
+
# @return [Sisimai::Mail::Mbox,Nil] Object or nil if the argument is not
|
22
|
+
# specified or does not exist
|
23
|
+
def initialize(argv1)
|
24
|
+
raise Errno::ENOENT unless File.exist?(argv1)
|
25
|
+
raise 'is not a file' unless File.ftype(argv1) == 'file'
|
26
|
+
|
27
|
+
@path = argv1
|
28
|
+
@dir = File.dirname(argv1)
|
29
|
+
@file = File.basename(argv1)
|
30
|
+
@size = File.size(argv1)
|
31
|
+
@offset = 0
|
32
|
+
@handle = File.open(argv1, 'r')
|
33
|
+
end
|
34
|
+
|
35
|
+
# Mbox reader, works as an iterator.
|
36
|
+
# @return [String] Contents of mbox
|
37
|
+
def read
|
38
|
+
return nil unless self.offset < self.size
|
39
|
+
|
40
|
+
seekoffset = self.offset || 0
|
41
|
+
filehandle = self.handle
|
42
|
+
readbuffer = ''
|
43
|
+
frombuffer = ''
|
44
|
+
|
45
|
+
begin
|
46
|
+
seekoffset = 0 if seekoffset < 0
|
47
|
+
filehandle.seek(seekoffset, 0)
|
48
|
+
|
49
|
+
filehandle.each_line do |r|
|
50
|
+
# Read the UNIX mbox file from 'From ' to the next 'From '
|
51
|
+
if r[0, 5] == 'From ' && readbuffer.size > 0
|
52
|
+
frombuffer = r
|
53
|
+
break
|
54
|
+
end
|
55
|
+
readbuffer << r
|
56
|
+
end
|
57
|
+
|
58
|
+
seekoffset = filehandle.pos - frombuffer.bytesize
|
59
|
+
frombuffer = ''
|
60
|
+
self.offset = seekoffset
|
61
|
+
filehandle.close unless self.offset < self.size
|
62
|
+
end
|
63
|
+
|
64
|
+
return readbuffer.to_s
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# Sisimai::Mail::STDIN is a reader for getting contents of each email from STDIN
|
2
|
+
module Sisimai
|
3
|
+
class Mail
|
4
|
+
class STDIN
|
5
|
+
# Imported from p5-Sisimail/lib/Sisimai/Mail/STDIN.pm
|
6
|
+
@@roaccessors = [
|
7
|
+
:path, # [String] Path to mbox
|
8
|
+
:name, # [String] File name of the mbox
|
9
|
+
:size, # [Integer] File size of the mbox
|
10
|
+
]
|
11
|
+
@@rwaccessors = [
|
12
|
+
:offset, # [Integer] Offset position for seeking
|
13
|
+
:handle, # [IO::File] File handle
|
14
|
+
]
|
15
|
+
@@roaccessors.each do |e| attr_reader e end
|
16
|
+
@@rwaccessors.each do |e| attr_accessor e end
|
17
|
+
|
18
|
+
# Constructor of Sisimai::Mail::STDIN
|
19
|
+
# @param [IO::STDIN] stdin Standard-In
|
20
|
+
# @return [Sisimai::Mail::STDIN] Object
|
21
|
+
def initialize(stdin = $stdin)
|
22
|
+
raise 'is not an IO object' unless stdin.is_a?(IO)
|
23
|
+
|
24
|
+
@path = '<STDIN>'
|
25
|
+
@name = '<STDIN>'
|
26
|
+
@size = nil
|
27
|
+
@offset = 0
|
28
|
+
@handle = stdin
|
29
|
+
end
|
30
|
+
|
31
|
+
# Mbox reader, works as a iterator.
|
32
|
+
# @return [String] Contents of mbox
|
33
|
+
def read
|
34
|
+
readhandle = self.handle
|
35
|
+
readbuffer = ''
|
36
|
+
|
37
|
+
begin
|
38
|
+
readhandle = STDIN unless readhandle
|
39
|
+
while r = readhandle.gets
|
40
|
+
break if readbuffer.size > 0 && r[0, 5] == 'From '
|
41
|
+
readbuffer << r
|
42
|
+
end
|
43
|
+
ensure
|
44
|
+
readhandle.close
|
45
|
+
end
|
46
|
+
|
47
|
+
return readbuffer
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
data/lib/sisimai/mda.rb
ADDED
@@ -0,0 +1,152 @@
|
|
1
|
+
module Sisimai
|
2
|
+
# Sisimai::MDA - Error message parser for MDA
|
3
|
+
module MDA
|
4
|
+
# Imported from p5-Sisimail/lib/Sisimai/MDA.pm
|
5
|
+
class << self
|
6
|
+
Re0 = {
|
7
|
+
:from => %r/\A(?:Mail Delivery Subsystem|MAILER-DAEMON|postmaster)/i,
|
8
|
+
}
|
9
|
+
Re1 = {
|
10
|
+
# dovecot/src/deliver/deliver.c
|
11
|
+
# 11: #define DEFAULT_MAIL_REJECTION_HUMAN_REASON \
|
12
|
+
# 12: "Your message to <%t> was automatically rejected:%n%r"
|
13
|
+
'dovecot' => %r/\AYour message to .+ was automatically rejected:\z/,
|
14
|
+
'mail.local' => %r/\Amail[.]local: /,
|
15
|
+
'procmail' => %r/\Aprocmail: /,
|
16
|
+
'maildrop' => %r/\Amaildrop: /,
|
17
|
+
'vpopmail' => %r/\Avdelivermail: /,
|
18
|
+
'vmailmgr' => %r/\Avdeliver: /,
|
19
|
+
}
|
20
|
+
Re2 = %r{\A(?>
|
21
|
+
Your[ ]message[ ]to[ ].+[ ]was[ ]automatically[ ]rejected:\z
|
22
|
+
|(?:mail[.]local|procmail|maildrop|vdelivermail|vdeliver):[ ]
|
23
|
+
)
|
24
|
+
}x
|
25
|
+
|
26
|
+
# dovecot/src/deliver/mail-send.c:94
|
27
|
+
ReFailure = {
|
28
|
+
'dovecot' => {
|
29
|
+
'userunknown' => %r/\AMailbox doesn't exist: /i,
|
30
|
+
'mailboxfull' => %r{\A(?:
|
31
|
+
Quota[ ]exceeded # Dovecot 1.2 dovecot/src/plugins/quota/quota.c
|
32
|
+
|Quota[ ]exceeded[ ][(]mailbox[ ]for[ ]user[ ]is[ ]full[)] # dovecot/src/plugins/quota/quota.c
|
33
|
+
|Not[ ]enough[ ]disk[ ]space
|
34
|
+
)
|
35
|
+
}xi,
|
36
|
+
},
|
37
|
+
'mail.local' => {
|
38
|
+
'userunknown' => %r{[:][ ](?:
|
39
|
+
unknown[ ]user[:]
|
40
|
+
|User[ ]unknown
|
41
|
+
|Invalid[ ]mailbox[ ]path
|
42
|
+
|User[ ]missing[ ]home[ ]directory
|
43
|
+
)
|
44
|
+
}xi,
|
45
|
+
'mailboxfull' => %r{(?:
|
46
|
+
Disc[ ]quota[ ]exceeded
|
47
|
+
|Mailbox[ ]full[ ]or[ ]quota[ ]exceeded
|
48
|
+
)
|
49
|
+
}xi,
|
50
|
+
'systemerror' => %r/Temporary file write error/i,
|
51
|
+
},
|
52
|
+
'procmail' => {
|
53
|
+
'mailboxfull' => %r/Quota exceeded while writing/i,
|
54
|
+
'systemfull' => %r/No space left to finish writing/i,
|
55
|
+
},
|
56
|
+
'maildrop' => {
|
57
|
+
'userunknown' => %r{(?:
|
58
|
+
Invalid[ ]user[ ]specified[.]
|
59
|
+
|Cannot[ ]find[ ]system[ ]user
|
60
|
+
)
|
61
|
+
}xi,
|
62
|
+
'mailboxfull' => %r/maildir over quota[.]\z/i,
|
63
|
+
},
|
64
|
+
'vpopmail' => {
|
65
|
+
'userunknown' => %r/Sorry, no mailbox here by that name[.]/i,
|
66
|
+
'filtered' => %r{(?:
|
67
|
+
account[ ]is[ ]locked[ ]email[ ]bounced
|
68
|
+
|user[ ]does[ ]not[ ]exist,[ ]but[ ]will[ ]deliver[ ]to[ ]
|
69
|
+
)
|
70
|
+
}xi,
|
71
|
+
'mailboxfull' => %r/(?:domain|user) is over quota/i,
|
72
|
+
},
|
73
|
+
'vmailmgr' => {
|
74
|
+
'userunknown' => %r{(?>
|
75
|
+
Invalid[ ]or[ ]unknown[ ](?:base[ ]user[ ]or[ ]domain|virtual[ ]user)
|
76
|
+
|User[ ]name[ ]does[ ]not[ ]refer[ ]to[ ]a[ ]virtual[ ]user/
|
77
|
+
)
|
78
|
+
}ix,
|
79
|
+
'mailboxfull' => %r/Delivery failed due to system quota violation/i,
|
80
|
+
},
|
81
|
+
}
|
82
|
+
|
83
|
+
# Parse message body and return reason and text
|
84
|
+
# @param [Hash] mhead Message header of a bounce email
|
85
|
+
# @options mhead [String] from From header
|
86
|
+
# @options mhead [String] date Date header
|
87
|
+
# @options mhead [String] subject Subject header
|
88
|
+
# @options mhead [Array] received Received headers
|
89
|
+
# @options mhead [String] others Other required headers
|
90
|
+
# @param [String] mbody Message body of a bounce email
|
91
|
+
# @return [Hash, Nil] Bounce data list and message/rfc822 part
|
92
|
+
# or Undef if it failed to parse or the
|
93
|
+
# arguments are missing
|
94
|
+
def scan(mhead, mbody)
|
95
|
+
return nil unless mhead
|
96
|
+
return nil unless mbody
|
97
|
+
return nil if mhead.keys.size == 0
|
98
|
+
return nil if mbody.empty?
|
99
|
+
|
100
|
+
return nil unless mhead['from'] =~ Re0[:from]
|
101
|
+
|
102
|
+
agentname0 = '' # [String] MDA name
|
103
|
+
reasonname = '' # [String] Error reason
|
104
|
+
bouncemesg = '' # [String] Error message
|
105
|
+
hasdivided = mbody.split("\n")
|
106
|
+
linebuffer = []
|
107
|
+
|
108
|
+
hasdivided.each do |e|
|
109
|
+
# Check each line with each MDA's symbol regular expression.
|
110
|
+
if agentname0 == ''
|
111
|
+
# Try to match with each regular expression
|
112
|
+
next unless e.size > 0;
|
113
|
+
next unless e =~ Re2
|
114
|
+
|
115
|
+
Re1.each_key do |f|
|
116
|
+
# Detect the agent name from the line
|
117
|
+
next unless e =~ Re1[f]
|
118
|
+
agentname0 = f
|
119
|
+
break
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Append error message lines to @linebuffer
|
124
|
+
linebuffer << e
|
125
|
+
break unless e.size > 0
|
126
|
+
end
|
127
|
+
|
128
|
+
return nil unless agentname0.size > 0
|
129
|
+
return nil unless linebuffer.size > 0
|
130
|
+
|
131
|
+
ReFailure[agentname0].each_key do |e|
|
132
|
+
# Detect an error reason from message patterns of the MDA.
|
133
|
+
linebuffer.each do |f|
|
134
|
+
# Try to match with each regular expression
|
135
|
+
next unless f =~ ReFailure[agentname0][e]
|
136
|
+
reasonname = e
|
137
|
+
bouncemesg = f
|
138
|
+
break
|
139
|
+
end
|
140
|
+
break if bouncemesg.size > 0 && reasonname.size > 0
|
141
|
+
end
|
142
|
+
|
143
|
+
return {
|
144
|
+
'mda' => agentname0,
|
145
|
+
'reason' => reasonname || '',
|
146
|
+
'message' => bouncemesg || '',
|
147
|
+
}
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
@@ -0,0 +1,510 @@
|
|
1
|
+
module Sisimai
|
2
|
+
# Sisimai::Message convert bounce email text to data structure. It resolve email
|
3
|
+
# text into an UNIX From line, the header part of the mail, delivery status, and
|
4
|
+
# RFC822 header part. When the email given as a argument of "new" method is not a
|
5
|
+
# bounce email, the method returns nil.
|
6
|
+
class Message
|
7
|
+
# Imported from p5-Sisimail/lib/Sisimai/Message.pm
|
8
|
+
require 'sisimai/arf'
|
9
|
+
require 'sisimai/mime'
|
10
|
+
require 'sisimai/order'
|
11
|
+
require 'sisimai/string'
|
12
|
+
require 'sisimai/rfc3834'
|
13
|
+
require 'sisimai/rfc5322'
|
14
|
+
|
15
|
+
@@rwaccessors = [
|
16
|
+
:from, # [String] UNIX From line
|
17
|
+
:header, # [Hash] Header part of a email
|
18
|
+
:ds, # [Array] Parsed data by Sisimai::MTA::*
|
19
|
+
:rfc822, # [Hash] Header part of the original message
|
20
|
+
]
|
21
|
+
@@rwaccessors.each { |e| attr_accessor e }
|
22
|
+
|
23
|
+
EndOfEmail = Sisimai::String.EOM
|
24
|
+
RFC822Head = Sisimai::RFC5322.HEADERFIELDS
|
25
|
+
RFC3834Set = Sisimai::RFC3834.headerlist.map { |e| e.downcase }
|
26
|
+
HeaderList = [
|
27
|
+
'from', 'to', 'date', 'subject', 'content-type', 'reply-to', 'message-id',
|
28
|
+
'received', 'content-transfer-encoding', 'return-path', 'x-mailer',
|
29
|
+
]
|
30
|
+
MultiHeads = { 'received' => true }
|
31
|
+
IgnoreList = { 'dkim-signature' => true }
|
32
|
+
Indicators = {
|
33
|
+
:begin => ( 1 << 1 ),
|
34
|
+
:endof => ( 1 << 2 ),
|
35
|
+
}
|
36
|
+
@@DefaultSet = Sisimai::Order.another
|
37
|
+
@@PatternSet = Sisimai::Order.by('subject')
|
38
|
+
@@ExtHeaders = Sisimai::Order.headers
|
39
|
+
@@ToBeLoaded = []
|
40
|
+
@@TryOnFirst = []
|
41
|
+
|
42
|
+
# Constructor of Sisimai::Message
|
43
|
+
# @param [String] data Email text data
|
44
|
+
# @param [Hash] argvs Module to be loaded
|
45
|
+
# @options argvs [String] data Entire email message
|
46
|
+
# @return [Sisimai::Message] Structured email data or Undef if each
|
47
|
+
# value of the arguments are missing
|
48
|
+
def initialize(data: '', **argvs)
|
49
|
+
return nil if data.empty?
|
50
|
+
|
51
|
+
email = data
|
52
|
+
email = email.scrub('?')
|
53
|
+
email = email.gsub("\r\n", "\n")
|
54
|
+
methodargv = { 'data' => email }
|
55
|
+
|
56
|
+
[:'load', :'order'].each do |e|
|
57
|
+
# Order of MTA, MSP modules
|
58
|
+
next unless argvs.key?(e)
|
59
|
+
next unless argvs[e].is_a? Array
|
60
|
+
next if argvs[e].empty?
|
61
|
+
methodargv[e.to_s] = argvs[e]
|
62
|
+
end
|
63
|
+
|
64
|
+
parameters = Sisimai::Message.make(methodargv)
|
65
|
+
return nil unless parameters
|
66
|
+
return nil unless parameters.key?('ds')
|
67
|
+
|
68
|
+
@from = parameters['from']
|
69
|
+
@header = parameters['header']
|
70
|
+
@ds = parameters['ds']
|
71
|
+
@rfc822 = parameters['rfc822']
|
72
|
+
end
|
73
|
+
|
74
|
+
# Check whether the object has valid content or not
|
75
|
+
# @return [True,False] returns true if the object is void
|
76
|
+
def void
|
77
|
+
return true unless @ds
|
78
|
+
return false
|
79
|
+
end
|
80
|
+
|
81
|
+
# Make data structure from the email message(a body part and headers)
|
82
|
+
# @param [Hash] argvs Email data
|
83
|
+
# @options argvs [String] data Entire email message
|
84
|
+
# @return [Hash] Resolved data structure
|
85
|
+
def self.make(argvs)
|
86
|
+
email = argvs['data']
|
87
|
+
|
88
|
+
processing = { 'from' => '', 'header' => {}, 'rfc822' => '', 'ds' => [] }
|
89
|
+
mtamodules = []
|
90
|
+
|
91
|
+
['load', 'order'].each do |e|
|
92
|
+
# The order of MTA modules specified by user
|
93
|
+
next unless argvs.key?(e)
|
94
|
+
next unless argvs[e].is_a? Array
|
95
|
+
next if argvs[e].empty?
|
96
|
+
|
97
|
+
mtamodules.concat(argvs['order']) if e == 'order'
|
98
|
+
next unless e == 'load'
|
99
|
+
|
100
|
+
# Load user defined MTA module
|
101
|
+
argvs['load'].each do |v|
|
102
|
+
# Load user defined MTA module
|
103
|
+
begin
|
104
|
+
require v.to_s.gsub('::', '/').downcase
|
105
|
+
rescue LoadError
|
106
|
+
warn ' ***warning: Failed to load ' + v
|
107
|
+
next
|
108
|
+
end
|
109
|
+
|
110
|
+
Module.const_get(v).headerlist.each do |w|
|
111
|
+
# Get header name which required user defined MTA module
|
112
|
+
@@ExtHeaders[w] ||= {}
|
113
|
+
@@ExtHeaders[w][v] = 1
|
114
|
+
end
|
115
|
+
@@ToBeLoaded << v
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
mtamodules.each do |e|
|
120
|
+
# Append the custom order of MTA modules
|
121
|
+
next if @@ToBeLoaded.index(e)
|
122
|
+
@@ToBeLoaded << e
|
123
|
+
end
|
124
|
+
|
125
|
+
# 0. Split email data to headers and a body part.
|
126
|
+
aftersplit = Sisimai::Message.divideup(email)
|
127
|
+
return nil if aftersplit.empty?
|
128
|
+
|
129
|
+
# 1. Initialize variables for setting the value of each email header.
|
130
|
+
@@TryOnFirst = []
|
131
|
+
|
132
|
+
# 2. Convert email headers from text to hash reference
|
133
|
+
processing['from'] = aftersplit['from']
|
134
|
+
processing['header'] = Sisimai::Message.headers(aftersplit['header'])
|
135
|
+
|
136
|
+
# 3. Check headers for detecting MTA/MSP module
|
137
|
+
if @@TryOnFirst.empty?
|
138
|
+
@@TryOnFirst.concat(Sisimai::Message.makeorder(processing['header']))
|
139
|
+
end
|
140
|
+
|
141
|
+
# 4. Rewrite message body for detecting the bounce reason
|
142
|
+
methodargv = { 'mail' => processing, 'body' => aftersplit['body'] }
|
143
|
+
bouncedata = Sisimai::Message.parse(methodargv)
|
144
|
+
|
145
|
+
return nil unless bouncedata
|
146
|
+
return nil if bouncedata.empty?
|
147
|
+
processing['ds'] = bouncedata['ds']
|
148
|
+
|
149
|
+
# 5. Rewrite headers of the original message in the body part
|
150
|
+
rfc822part = bouncedata['rfc822']
|
151
|
+
rfc822part = aftersplit['body'] if rfc822part.empty?
|
152
|
+
processing['rfc822'] = Sisimai::Message.takeapart(rfc822part)
|
153
|
+
|
154
|
+
return processing
|
155
|
+
end
|
156
|
+
|
157
|
+
# Divide email data up headers and a body part.
|
158
|
+
# @param [String] email Email data
|
159
|
+
# @return [Hash] Email data after split
|
160
|
+
def self.divideup(email)
|
161
|
+
return {} if email.empty?
|
162
|
+
|
163
|
+
email = email.scrub('?')
|
164
|
+
email = email.gsub(/[ \t]+$/, '')
|
165
|
+
email = email.gsub(/^[ \t]+$/, '')
|
166
|
+
hasdivided = email.split("\n")
|
167
|
+
return {} if hasdivided.empty?
|
168
|
+
|
169
|
+
readcursor = 0
|
170
|
+
aftersplit = { 'from' => '', 'header' => '', 'body' => '' }
|
171
|
+
pseudofrom = 'MAILER-DAEMON Tue Feb 11 00:00:00 2014'
|
172
|
+
|
173
|
+
if hasdivided[0][0, 5] == 'From '
|
174
|
+
# From MAILER-DAEMON Tue Feb 11 00:00:00 2014
|
175
|
+
aftersplit['from'] = hasdivided.shift
|
176
|
+
aftersplit['from'] = aftersplit['from'].delete("\n").delete("\r")
|
177
|
+
end
|
178
|
+
|
179
|
+
# Split email data to headers and a body part.
|
180
|
+
hasdivided.each do |e|
|
181
|
+
# Split email data to headers and a body part.
|
182
|
+
e = e.delete("\r").delete("\n")
|
183
|
+
|
184
|
+
if readcursor & Indicators[:endof] > 0
|
185
|
+
# The body part of the email
|
186
|
+
aftersplit['body'] += e + "\n"
|
187
|
+
|
188
|
+
else
|
189
|
+
# The boundary for splitting headers and a body part does not
|
190
|
+
# appeare yet.
|
191
|
+
if e.empty?
|
192
|
+
# Blank line, it is a boundary of headers and a body part
|
193
|
+
readcursor |= Indicators[:endof] if readcursor & Indicators[:begin] > 0
|
194
|
+
|
195
|
+
else
|
196
|
+
# The header part of the email
|
197
|
+
aftersplit['header'] += e + "\n"
|
198
|
+
readcursor |= Indicators[:begin]
|
199
|
+
end
|
200
|
+
end
|
201
|
+
end
|
202
|
+
return {} if aftersplit['header'].empty?
|
203
|
+
return {} if aftersplit['body'].empty?
|
204
|
+
|
205
|
+
aftersplit['from'] = pseudofrom if aftersplit['from'].empty?
|
206
|
+
return aftersplit
|
207
|
+
end
|
208
|
+
|
209
|
+
# Convert email headers from text to hash reference
|
210
|
+
# @param [String] heads Email header data
|
211
|
+
# @return [Hash] Structured email header data
|
212
|
+
def self.headers(heads)
|
213
|
+
return nil unless heads
|
214
|
+
|
215
|
+
currheader = ''
|
216
|
+
allheaders = {}
|
217
|
+
structured = {}
|
218
|
+
|
219
|
+
HeaderList.each { |e| structured[e] = nil }
|
220
|
+
HeaderList.each { |e| allheaders[e] = true }
|
221
|
+
RFC3834Set.each { |e| allheaders[e] = true }
|
222
|
+
MultiHeads.each_key { |e| structured[e.downcase] = [] }
|
223
|
+
@@ExtHeaders.each_key { |e| allheaders[e] = true }
|
224
|
+
|
225
|
+
heads.split("\n").each do |e|
|
226
|
+
# Convert email headers to hash
|
227
|
+
if cv = e.match(/\A([^ ]+?)[:][ ]*(.+?)\z/)
|
228
|
+
# split the line into a header name and a header content
|
229
|
+
lhs = cv[1]
|
230
|
+
rhs = cv[2]
|
231
|
+
|
232
|
+
currheader = lhs.downcase
|
233
|
+
next unless allheaders.key?(currheader)
|
234
|
+
|
235
|
+
if MultiHeads.key?(currheader)
|
236
|
+
# Such as 'Received' header, there are multiple headers in a single
|
237
|
+
# email message.
|
238
|
+
rhs = rhs.tr("\t", ' ')
|
239
|
+
rhs = rhs.squeeze(' ')
|
240
|
+
structured[currheader] << rhs
|
241
|
+
|
242
|
+
else
|
243
|
+
# Other headers except "Received" and so on
|
244
|
+
if @@ExtHeaders[currheader]
|
245
|
+
# MTA specific header
|
246
|
+
@@TryOnFirst.concat(@@ExtHeaders[currheader].keys)
|
247
|
+
end
|
248
|
+
structured[currheader] = rhs
|
249
|
+
end
|
250
|
+
|
251
|
+
elsif cv = e.match(/\A[ \t]+(.+?)\z/)
|
252
|
+
# Ignore header?
|
253
|
+
next if IgnoreList[currheader]
|
254
|
+
|
255
|
+
# Header line continued from the previous line
|
256
|
+
if structured[currheader].is_a? Array
|
257
|
+
# Concatenate a header which have multi-lines such as 'Received'
|
258
|
+
structured[currheader][-1] += ' ' + cv[1]
|
259
|
+
|
260
|
+
else
|
261
|
+
structured[currheader] ||= ''
|
262
|
+
structured[currheader] += ' ' + cv[1]
|
263
|
+
end
|
264
|
+
end
|
265
|
+
end
|
266
|
+
return structured
|
267
|
+
end
|
268
|
+
|
269
|
+
# Check headers for detecting MTA/MSP module and returns the order of modules
|
270
|
+
# @param [Hash] heads Email header data
|
271
|
+
# @return [Array] Order of MTA/MSP modules
|
272
|
+
def self.makeorder(heads)
|
273
|
+
return [] unless heads
|
274
|
+
return [] unless heads['subject']
|
275
|
+
return [] if heads['subject'].empty?
|
276
|
+
order = []
|
277
|
+
|
278
|
+
# Try to match the value of "Subject" with patterns generated by
|
279
|
+
# Sisimai::Order->by('subject') method
|
280
|
+
@@PatternSet.each_key do |e|
|
281
|
+
# Get MTA list from the subject header
|
282
|
+
next unless heads['subject'] =~ e
|
283
|
+
|
284
|
+
# Matched and push MTA list
|
285
|
+
order.concat(@@PatternSet[e])
|
286
|
+
break
|
287
|
+
end
|
288
|
+
return order
|
289
|
+
end
|
290
|
+
|
291
|
+
# Take each email header in the original message apart
|
292
|
+
# @param [String] heads The original message header
|
293
|
+
# @return [Hash] Structured message headers
|
294
|
+
def self.takeapart(heads)
|
295
|
+
return {} unless heads
|
296
|
+
|
297
|
+
# Convert from string to hash reference
|
298
|
+
heads = heads.gsub(/^[>]+[ ]/m, '')
|
299
|
+
|
300
|
+
takenapart = {}
|
301
|
+
hasdivided = heads.split("\n")
|
302
|
+
previousfn = '' # Previous field name
|
303
|
+
borderline = '__MIME_ENCODED_BOUNDARY__'
|
304
|
+
mimeborder = {}
|
305
|
+
|
306
|
+
hasdivided.each do |e|
|
307
|
+
# Header name as a key, The value of header as a value
|
308
|
+
if cv = e.match(/\A([-0-9A-Za-z]+?)[:][ ]*(.*)\z/)
|
309
|
+
# Header
|
310
|
+
lhs = cv[1].downcase
|
311
|
+
rhs = cv[2]
|
312
|
+
previousfn = ''
|
313
|
+
|
314
|
+
next unless RFC822Head.key?(lhs)
|
315
|
+
previousfn = lhs
|
316
|
+
takenapart[previousfn] = rhs unless takenapart[previousfn]
|
317
|
+
|
318
|
+
else
|
319
|
+
# Continued line from the previous line
|
320
|
+
next unless e =~ /\A[ \t]+/
|
321
|
+
next if previousfn.empty?
|
322
|
+
|
323
|
+
# Concatenate the line if it is the value of required header
|
324
|
+
if Sisimai::MIME.is_mimeencoded(e)
|
325
|
+
# The line is MIME-Encoded test
|
326
|
+
if previousfn == 'subject'
|
327
|
+
# Subject: header
|
328
|
+
takenapart[previousfn] += borderline + e
|
329
|
+
|
330
|
+
else
|
331
|
+
# Is not Subject header
|
332
|
+
takenapart[previousfn] += e
|
333
|
+
end
|
334
|
+
mimeborder[previousfn] = true
|
335
|
+
|
336
|
+
else
|
337
|
+
# ASCII Characters only: Not MIME-Encoded
|
338
|
+
e = e.lstrip
|
339
|
+
takenapart[previousfn] += e
|
340
|
+
mimeborder[previousfn] ||= false
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
|
345
|
+
if takenapart['subject']
|
346
|
+
# Convert MIME-Encoded subject
|
347
|
+
v = takenapart['subject']
|
348
|
+
|
349
|
+
if Sisimai::String.is_8bit(v)
|
350
|
+
# The value of ``Subject'' header is including multibyte character,
|
351
|
+
# is not MIME-Encoded text.
|
352
|
+
v = 'MULTIBYTE CHARACTERS HAVE BEEN REMOVED'
|
353
|
+
|
354
|
+
else
|
355
|
+
# MIME-Encoded subject field or ASCII characters only
|
356
|
+
r = []
|
357
|
+
if mimeborder['subject']
|
358
|
+
# split the value of Subject by $borderline
|
359
|
+
v.split(borderline).each do |m|
|
360
|
+
# Insert value to the array if the string is MIME encoded text
|
361
|
+
r << m if Sisimai::MIME.is_mimeencoded(m)
|
362
|
+
end
|
363
|
+
else
|
364
|
+
# Subject line is not MIME encoded
|
365
|
+
r << v
|
366
|
+
end
|
367
|
+
v = Sisimai::MIME.mimedecode(r)
|
368
|
+
end
|
369
|
+
takenapart['subject'] = v
|
370
|
+
end
|
371
|
+
return takenapart
|
372
|
+
end
|
373
|
+
|
374
|
+
# Parse bounce mail with each MTA/MSP module
|
375
|
+
# @param [Hash] argvs Processing message entity.
|
376
|
+
# @param options argvs [Hash] mail Email message entity
|
377
|
+
# @param options mail [String] from From line of mbox
|
378
|
+
# @param options mail [Hash] header Email header data
|
379
|
+
# @param options mail [String] rfc822 Original message part
|
380
|
+
# @param options mail [Array] ds Delivery status list(parsed data)
|
381
|
+
# @param options argvs [String] body Email message body
|
382
|
+
# @param options argvs [Array] load MTA/MSP module list to load on first
|
383
|
+
# @return [Hash] Parsed and structured bounce mails
|
384
|
+
def self.parse(argvs)
|
385
|
+
mesgentity = argvs['mail']
|
386
|
+
bodystring = argvs['body']
|
387
|
+
mailheader = mesgentity['header']
|
388
|
+
|
389
|
+
return nil unless argvs['mail']
|
390
|
+
return nil unless argvs['body']
|
391
|
+
|
392
|
+
# PRECHECK_EACH_HEADER:
|
393
|
+
# Set empty string if the value is nil
|
394
|
+
mailheader['from'] ||= ''
|
395
|
+
mailheader['subject'] ||= ''
|
396
|
+
mailheader['content-type'] ||= ''
|
397
|
+
|
398
|
+
# Decode BASE64 Encoded message body, rewrite.
|
399
|
+
mesgformat = (mailheader['content-type'] || '').downcase
|
400
|
+
ctencoding = (mailheader['content-transfer-encoding'] || '').downcase
|
401
|
+
|
402
|
+
if mesgformat =~ %r|text/plain;|
|
403
|
+
# Content-Type: text/plain; charset=UTF-8
|
404
|
+
if ctencoding == 'base64' || ctencoding == 'quoted-printable'
|
405
|
+
# Content-Transfer-Encoding: base64
|
406
|
+
# Content-Transfer-Encoding: quoted-printable
|
407
|
+
if ctencoding == 'base64'
|
408
|
+
# Content-Transfer-Encoding: base64
|
409
|
+
bodystring = Sisimai::MIME.base64d(bodystring)
|
410
|
+
|
411
|
+
else
|
412
|
+
# Content-Transfer-Encoding: quoted-printable
|
413
|
+
bodystring = Sisimai::MIME.qprintd(bodystring)
|
414
|
+
end
|
415
|
+
end
|
416
|
+
end
|
417
|
+
|
418
|
+
# EXPAND_FORWARDED_MESSAGE:
|
419
|
+
# Check whether or not the message is a bounce mail.
|
420
|
+
# Pre-Process email body if it is a forwarded bounce message.
|
421
|
+
# Get the original text when the subject begins from 'fwd:' or 'fw:'
|
422
|
+
if mailheader['subject'] =~ /\A[ \t]*fwd?:/i
|
423
|
+
# Delete quoted strings, quote symbols(>)
|
424
|
+
bodystring = bodystring.gsub(/^[>]+[ ]/m, '')
|
425
|
+
bodystring = bodystring.gsub(/^[>]$/m, '')
|
426
|
+
end
|
427
|
+
bodystring += EndOfEmail
|
428
|
+
haveloaded = {}
|
429
|
+
scannedset = nil
|
430
|
+
|
431
|
+
catch :SCANNER do
|
432
|
+
loop do
|
433
|
+
# 1. Sisimai::ARF
|
434
|
+
# 2. User-Defined Module
|
435
|
+
# 3. MTA Module Candidates to be tried on first
|
436
|
+
# 4. Sisimai::MTA::* and MSP::*
|
437
|
+
# 5. Sisimai::RFC3464
|
438
|
+
# 6. Sisimai::RFC3834
|
439
|
+
#
|
440
|
+
if Sisimai::ARF.is_arf(mailheader)
|
441
|
+
# Feedback Loop message
|
442
|
+
scannedset = Sisimai::ARF.scan(mailheader, bodystring)
|
443
|
+
throw :SCANNER if scannedset
|
444
|
+
end
|
445
|
+
|
446
|
+
@@ToBeLoaded.each do |r|
|
447
|
+
# Call user defined MTA modules
|
448
|
+
next if haveloaded[r]
|
449
|
+
begin
|
450
|
+
require r.gsub('::', '/').downcase
|
451
|
+
rescue LoadError => ce
|
452
|
+
warn ' ***warning: Failed to load ' + ce.to_s
|
453
|
+
next
|
454
|
+
end
|
455
|
+
scannedset = Module.const_get(r).scan(mailheader, bodystring)
|
456
|
+
haveloaded[r] = true
|
457
|
+
throw :SCANNER if scannedset
|
458
|
+
end
|
459
|
+
|
460
|
+
@@TryOnFirst.each do |r|
|
461
|
+
# Try MTA module candidates which are detected from MTA specific
|
462
|
+
# mail headers on first
|
463
|
+
next if haveloaded.key?(r)
|
464
|
+
begin
|
465
|
+
require r.gsub('::', '/').downcase
|
466
|
+
rescue LoadError => ce
|
467
|
+
warn ' ***warning: ' + ce.to_s
|
468
|
+
next
|
469
|
+
end
|
470
|
+
scannedset = Module.const_get(r).scan(mailheader, bodystring)
|
471
|
+
haveloaded[r] = true
|
472
|
+
throw :SCANNER if scannedset
|
473
|
+
end
|
474
|
+
|
475
|
+
@@DefaultSet.each do |r|
|
476
|
+
# MTA/MSP modules which does not have MTA specific header and did
|
477
|
+
# not match with any regular expressions of Subject header.
|
478
|
+
next if haveloaded.key?(r)
|
479
|
+
begin
|
480
|
+
scannedset = Module.const_get(r).scan(mailheader, bodystring)
|
481
|
+
haveloaded[r] = true
|
482
|
+
throw :SCANNER if scannedset
|
483
|
+
rescue => ce
|
484
|
+
warn ' ***warning: ' + ce.to_s
|
485
|
+
next
|
486
|
+
end
|
487
|
+
|
488
|
+
end
|
489
|
+
|
490
|
+
# When the all of Sisimai::MTA::* modules did not return bounce data,
|
491
|
+
# call Sisimai::RFC3464;
|
492
|
+
require 'sisimai/rfc3464'
|
493
|
+
scannedset = Sisimai::RFC3464.scan(mailheader, bodystring)
|
494
|
+
break if scannedset
|
495
|
+
|
496
|
+
# Try to parse the message as auto reply message defined in RFC3834
|
497
|
+
require 'sisimai/rfc3834'
|
498
|
+
scannedset = Sisimai::RFC3834.scan(mailheader, bodystring)
|
499
|
+
break if scannedset
|
500
|
+
|
501
|
+
# as of now, we have no sample email for coding this block
|
502
|
+
break
|
503
|
+
end
|
504
|
+
end
|
505
|
+
return scannedset
|
506
|
+
end
|
507
|
+
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|