├── .github └── workflows │ └── test.yml ├── .gitignore ├── CHANGELOG.rdoc ├── CONTRIBUTING.md ├── Gemfile ├── MIT-LICENSE ├── README.md ├── Rakefile ├── lib ├── mail.rb └── mail │ ├── attachments_list.rb │ ├── body.rb │ ├── configuration.rb │ ├── constants.rb │ ├── elements.rb │ ├── elements │ ├── address.rb │ ├── address_list.rb │ ├── content_disposition_element.rb │ ├── content_location_element.rb │ ├── content_transfer_encoding_element.rb │ ├── content_type_element.rb │ ├── date_time_element.rb │ ├── envelope_from_element.rb │ ├── message_ids_element.rb │ ├── mime_version_element.rb │ ├── phrase_list.rb │ └── received_element.rb │ ├── encodings.rb │ ├── encodings │ ├── 7bit.rb │ ├── 8bit.rb │ ├── base64.rb │ ├── binary.rb │ ├── identity.rb │ ├── quoted_printable.rb │ ├── transfer_encoding.rb │ └── unix_to_unix.rb │ ├── envelope.rb │ ├── field.rb │ ├── field_list.rb │ ├── fields.rb │ ├── fields │ ├── bcc_field.rb │ ├── cc_field.rb │ ├── comments_field.rb │ ├── common_address_field.rb │ ├── common_date_field.rb │ ├── common_field.rb │ ├── common_message_id_field.rb │ ├── content_description_field.rb │ ├── content_disposition_field.rb │ ├── content_id_field.rb │ ├── content_location_field.rb │ ├── content_transfer_encoding_field.rb │ ├── content_type_field.rb │ ├── date_field.rb │ ├── from_field.rb │ ├── in_reply_to_field.rb │ ├── keywords_field.rb │ ├── message_id_field.rb │ ├── mime_version_field.rb │ ├── named_structured_field.rb │ ├── named_unstructured_field.rb │ ├── optional_field.rb │ ├── parameter_hash.rb │ ├── received_field.rb │ ├── references_field.rb │ ├── reply_to_field.rb │ ├── resent_bcc_field.rb │ ├── resent_cc_field.rb │ ├── resent_date_field.rb │ ├── resent_from_field.rb │ ├── resent_message_id_field.rb │ ├── resent_sender_field.rb │ ├── resent_to_field.rb │ ├── return_path_field.rb │ ├── sender_field.rb │ ├── structured_field.rb │ ├── subject_field.rb │ ├── to_field.rb │ └── unstructured_field.rb │ ├── header.rb │ ├── indifferent_hash.rb │ ├── mail.rb │ ├── matchers │ ├── attachment_matchers.rb │ └── has_sent_mail.rb │ ├── message.rb │ ├── multibyte.rb │ ├── multibyte │ ├── chars.rb │ ├── unicode.rb │ └── utils.rb │ ├── network.rb │ ├── network │ ├── delivery_methods │ │ ├── exim.rb │ │ ├── file_delivery.rb │ │ ├── logger_delivery.rb │ │ ├── sendmail.rb │ │ ├── smtp.rb │ │ ├── smtp_connection.rb │ │ └── test_mailer.rb │ └── retriever_methods │ │ ├── base.rb │ │ ├── imap.rb │ │ ├── pop3.rb │ │ └── test_retriever.rb │ ├── parser_tools.rb │ ├── parsers.rb │ ├── parsers │ ├── address_lists_parser.rb │ ├── address_lists_parser.rl │ ├── content_disposition_parser.rb │ ├── content_disposition_parser.rl │ ├── content_location_parser.rb │ ├── content_location_parser.rl │ ├── content_transfer_encoding_parser.rb │ ├── content_transfer_encoding_parser.rl │ ├── content_type_parser.rb │ ├── content_type_parser.rl │ ├── date_time_parser.rb │ ├── date_time_parser.rl │ ├── envelope_from_parser.rb │ ├── envelope_from_parser.rl │ ├── message_ids_parser.rb │ ├── message_ids_parser.rl │ ├── mime_version_parser.rb │ ├── mime_version_parser.rl │ ├── phrase_lists_parser.rb │ ├── phrase_lists_parser.rl │ ├── received_parser.rb │ ├── received_parser.rl │ ├── rfc2045_content_transfer_encoding.rl │ ├── rfc2045_content_type.rl │ ├── rfc2045_mime.rl │ ├── rfc2183_content_disposition.rl │ ├── rfc3629_utf8.rl │ ├── rfc5234_abnf_core_rules.rl │ ├── rfc5322.rl │ ├── rfc5322_address.rl │ ├── rfc5322_date_time.rl │ └── rfc5322_lexical_tokens.rl │ ├── part.rb │ ├── parts_list.rb │ ├── smtp_envelope.rb │ ├── utilities.rb │ ├── values │ └── unicode_tables.dat │ ├── version.rb │ └── yaml.rb ├── mail.gemspec ├── rakelib ├── corpus.rake ├── generate_tables └── ragel.rake ├── spec ├── environment.rb ├── fixtures │ ├── attachments │ │ ├── basic_email.eml │ │ ├── test.gif │ │ ├── test.jpg │ │ ├── test.pdf │ │ ├── test.png │ │ ├── test.tiff │ │ ├── test.zip │ │ └── てすと.txt │ └── emails │ │ ├── .gitattributes │ │ ├── attachment_emails │ │ ├── attachment_content_disposition.eml │ │ ├── attachment_content_location.eml │ │ ├── attachment_message_rfc822.eml │ │ ├── attachment_message_rfc822_inline_image.eml │ │ ├── attachment_nonascii_filename.eml │ │ ├── attachment_only_email.eml │ │ ├── attachment_pdf.eml │ │ ├── attachment_pdf_lf.eml │ │ ├── attachment_pdf_non_ascii.eml │ │ ├── attachment_pdf_non_ascii_lf.eml │ │ ├── attachment_with_base64_encoded_name.eml │ │ ├── attachment_with_encoded_name.eml │ │ ├── attachment_with_quoted_filename.eml │ │ └── attachment_with_unquoted_name.eml │ │ ├── error_emails │ │ ├── bad_date_header.eml │ │ ├── bad_date_header2.eml │ │ ├── bad_encoded_subject.eml │ │ ├── bad_subject.eml │ │ ├── cant_parse_from.eml │ │ ├── content_transfer_encoding_7-bit.eml │ │ ├── content_transfer_encoding_empty.eml │ │ ├── content_transfer_encoding_plain.eml │ │ ├── content_transfer_encoding_qp_with_space.eml │ │ ├── content_transfer_encoding_spam.eml │ │ ├── content_transfer_encoding_text-html.eml │ │ ├── content_transfer_encoding_with_8bits.eml │ │ ├── content_transfer_encoding_with_semi_colon.eml │ │ ├── content_transfer_encoding_x_uuencode.eml │ │ ├── empty_group_lists.eml │ │ ├── empty_in_reply_to.eml │ │ ├── encoding_madness.eml │ │ ├── header_fields_with_empty_values.eml │ │ ├── invalid_subject_characters.eml │ │ ├── missing_body.eml │ │ ├── missing_content_disposition.eml │ │ ├── multiple_content_types.eml │ │ ├── multiple_invalid_content_dispositions.eml │ │ ├── multiple_references_with_one_invalid.eml │ │ ├── must_supply_encoding.eml │ │ ├── new_line_in_to_header.eml │ │ ├── trademark_character_in_subject.eml │ │ └── weird_to_header.eml │ │ ├── mime_emails │ │ ├── email_with_similar_boundaries.eml │ │ ├── raw_email11.eml │ │ ├── raw_email12.eml │ │ ├── raw_email2.eml │ │ ├── raw_email4.eml │ │ ├── raw_email7.eml │ │ ├── raw_email_encoded_stack_level_too_deep.eml │ │ ├── raw_email_with_binary_encoded.eml │ │ ├── raw_email_with_illegal_boundary.eml │ │ ├── raw_email_with_mimepart_without_content_type.eml │ │ ├── raw_email_with_multipart_mixed_quoted_boundary.eml │ │ ├── raw_email_with_nested_attachment.eml │ │ ├── raw_email_with_quoted_illegal_boundary.eml │ │ ├── sig_only_email.eml │ │ └── two_from_in_message.eml │ │ ├── multi_charset │ │ ├── japanese.eml │ │ ├── japanese_attachment.eml │ │ ├── japanese_attachment_long_name.eml │ │ ├── japanese_iso_2022.eml │ │ ├── japanese_shift_jis.eml │ │ └── ks_c_5601-1987.eml │ │ ├── multipart_report_emails │ │ ├── multi_address_bounce1.eml │ │ ├── multi_address_bounce2.eml │ │ ├── multipart_report_multiple_status.eml │ │ ├── report_422.eml │ │ └── report_530.eml │ │ ├── plain_emails │ │ ├── basic_email.eml │ │ ├── basic_email_lf.eml │ │ ├── mix_caps_content_type.eml │ │ ├── raw_email.eml │ │ ├── raw_email10.eml │ │ ├── raw_email5.eml │ │ ├── raw_email6.eml │ │ ├── raw_email8.eml │ │ ├── raw_email_bad_time.eml │ │ ├── raw_email_double_at_in_header.eml │ │ ├── raw_email_incorrect_header.eml │ │ ├── raw_email_multiple_from.eml │ │ ├── raw_email_quoted_with_0d0a.eml │ │ ├── raw_email_reply.eml │ │ ├── raw_email_simple.eml │ │ ├── raw_email_string_in_date_field.eml │ │ ├── raw_email_trailing_dot.eml │ │ ├── raw_email_with_at_display_name.eml │ │ ├── raw_email_with_bad_date.eml │ │ └── raw_email_with_partially_quoted_subject.eml │ │ ├── rfc2822 │ │ ├── example01.eml │ │ ├── example02.eml │ │ ├── example03.eml │ │ ├── example04.eml │ │ ├── example05.eml │ │ ├── example06.eml │ │ ├── example07.eml │ │ ├── example08.eml │ │ ├── example09.eml │ │ ├── example10.eml │ │ ├── example11.eml │ │ ├── example12.eml │ │ ├── example13.eml │ │ └── example14.eml │ │ ├── rfc6532 │ │ └── utf8_headers.eml │ │ └── sample_output_multipart ├── mail │ ├── attachments_list_spec.rb │ ├── body_spec.rb │ ├── configuration_spec.rb │ ├── core_extensions_spec.rb │ ├── elements │ │ ├── address_list_spec.rb │ │ ├── address_spec.rb │ │ ├── date_time_element_spec.rb │ │ ├── envelope_from_element_spec.rb │ │ ├── message_ids_element_spec.rb │ │ ├── phrase_list_spec.rb │ │ └── received_element_spec.rb │ ├── encoding_spec.rb │ ├── encodings │ │ ├── base64_spec.rb │ │ ├── quoted_printable_spec.rb │ │ ├── transfer_encoding_spec.rb │ │ └── unix_to_unix_spec.rb │ ├── encodings_spec.rb │ ├── example_emails_spec.rb │ ├── field_list_spec.rb │ ├── field_spec.rb │ ├── fields │ │ ├── address_container_spec.rb │ │ ├── bcc_field_spec.rb │ │ ├── cc_field_spec.rb │ │ ├── comments_field_spec.rb │ │ ├── common_address_spec.rb │ │ ├── common_date_spec.rb │ │ ├── common_field_spec.rb │ │ ├── common_message_id_spec.rb │ │ ├── content_description_field_spec.rb │ │ ├── content_disposition_field_spec.rb │ │ ├── content_id_field_spec.rb │ │ ├── content_location_field_spec.rb │ │ ├── content_transfer_encoding_field_spec.rb │ │ ├── content_type_field_spec.rb │ │ ├── date_field_spec.rb │ │ ├── envelope_spec.rb │ │ ├── from_field_spec.rb │ │ ├── in_reply_to_field_spec.rb │ │ ├── keywords_field_spec.rb │ │ ├── message_id_field_spec.rb │ │ ├── mime_version_field_spec.rb │ │ ├── parameter_hash_spec.rb │ │ ├── received_field_spec.rb │ │ ├── references_field_spec.rb │ │ ├── reply_to_field_spec.rb │ │ ├── resent_bcc_field_spec.rb │ │ ├── resent_cc_field_spec.rb │ │ ├── resent_date_field_spec.rb │ │ ├── resent_from_field_spec.rb │ │ ├── resent_message_id_field_spec.rb │ │ ├── resent_sender_field_spec.rb │ │ ├── resent_to_field_spec.rb │ │ ├── return_path_field_spec.rb │ │ ├── sender_field_spec.rb │ │ ├── structured_field_spec.rb │ │ ├── to_field_spec.rb │ │ └── unstructured_field_spec.rb │ ├── header_spec.rb │ ├── mail_spec.rb │ ├── message_spec.rb │ ├── mime_messages_spec.rb │ ├── multibyte_spec.rb │ ├── multipart_report_spec.rb │ ├── network │ │ ├── delivery_methods │ │ │ ├── exim_spec.rb │ │ │ ├── file_delivery_spec.rb │ │ │ ├── logger_delivery_spec.rb │ │ │ ├── sendmail_spec.rb │ │ │ ├── smtp_connection_spec.rb │ │ │ ├── smtp_spec.rb │ │ │ └── test_mailer_spec.rb │ │ └── retriever_methods │ │ │ ├── imap_spec.rb │ │ │ ├── pop3_spec.rb │ │ │ └── test_retriever_spec.rb │ ├── network_spec.rb │ ├── parsers │ │ ├── address_lists_parser_spec.rb │ │ └── content_transfer_encoding_parser_spec.rb │ ├── part_spec.rb │ ├── parts_list_spec.rb │ ├── round_tripping_spec.rb │ ├── utilities_spec.rb │ └── yaml_spec.rb ├── matchers │ └── break_down_to.rb ├── matchers_spec.rb └── spec_helper.rb └── tools └── console /.gitignore: -------------------------------------------------------------------------------- 1 | /.bundle 2 | /.rbenv-vars 3 | /.ruby-version 4 | /.rvmrc 5 | /bin 6 | /corpus 7 | /coverage 8 | /Gemfile.lock 9 | /gems 10 | /lib/mail/parsers/ragel/ruby/machines/*.dot 11 | /lib/mail/parsers/ragel/ruby/machines/*.svg 12 | /mail-*.gem 13 | /rdoc 14 | -------------------------------------------------------------------------------- /CHANGELOG.rdoc: -------------------------------------------------------------------------------- 1 | == Version 2.9.0 (unreleased) 2 | 3 | Breaking changes: 4 | * Mail::Field::FIELDS_MAP now contains class names, not Class instances (c960657) 5 | 6 | Compatibility: 7 | 8 | * Update MIME-Version to have correct case per RFC 2045 @mikel 9 | 10 | Features: 11 | 12 | * Updated README to improve around sending multipart mail @kapfenho 13 | * Add delivery_interceptors method to Mail class to fetch registered interceptors @ghousemohamed 14 | 15 | Code Improvements: 16 | 17 | * Use Rake's default rakelib/ directory @olleolleolle 18 | * refactor: Use Dir.glob only once in gemspec's "files" directive @olleolleolle 19 | * Configure RSpec's zero-monkey patching mode @olleolleolle 20 | * Added support for JRuby 9.4 @mikel 21 | * Prefer `__dir__` @olleolleolle 22 | 23 | Bug Fixes: 24 | 25 | * Regression: Preserve message-level charset when adding parts (related to Rails ActionMailer) @shields 26 | * Regression: Adding a part should not reset the mail's charset to nil @railsbob 27 | 28 | Performance: 29 | 30 | * reduce object allocations by replacing =~ and Regexp#match by Regexp#match? @ahorek 31 | * reduce object allocations by replacing String#unpack[0] by String#unpack1 @ahorek 32 | 33 | 34 | Please check [2-8-stable](https://github.com/mikel/mail/blob/2-8-stable/CHANGELOG.rdoc) for previous changes. 35 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gemspec 4 | 5 | if ENV['MBCHARS'] # see spec/environment.rb 6 | if RUBY_VERSION < '2.7.0' 7 | gem 'activesupport', '< 6' 8 | else 9 | gem 'activesupport', :git => 'https://github.com/rails/rails', :branch => 'main' 10 | end 11 | end 12 | 13 | gem 'jruby-openssl', :platforms => :jruby 14 | 15 | gem 'mini_mime' 16 | 17 | gem 'byebug', :platforms => :mri 18 | -------------------------------------------------------------------------------- /MIT-LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2009-2016 Mikel Lindsaar 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining 4 | a copy of this software and associated documentation files (the 5 | 'Software'), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to 8 | permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be 12 | included in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 15 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 18 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 19 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 20 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | if !ENV["APPRAISAL_INITIALIZED"] && !ENV["CI"] 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('Gemfile', __dir__) 3 | end 4 | require 'rubygems' 5 | require 'bundler/setup' 6 | 7 | require 'rake/testtask' 8 | require 'rspec/core/rake_task' 9 | 10 | desc "Build a gem file" 11 | task :build do 12 | system "gem build mail.gemspec" 13 | end 14 | 15 | task :default => :spec 16 | 17 | RSpec::Core::RakeTask.new(:spec) do |t| 18 | t.ruby_opts = '-w' 19 | t.rspec_opts = %w(--backtrace --color) 20 | end 21 | -------------------------------------------------------------------------------- /lib/mail.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | module Mail # :doc: 4 | 5 | require 'date' 6 | require 'shellwords' 7 | 8 | require 'uri' 9 | require 'net/smtp' 10 | require 'mini_mime' 11 | 12 | require 'mail/version' 13 | 14 | require 'mail/indifferent_hash' 15 | 16 | require 'mail/multibyte' 17 | 18 | require 'mail/constants' 19 | require 'mail/utilities' 20 | require 'mail/configuration' 21 | 22 | @@autoloads = {} 23 | def self.register_autoload(name, path) 24 | @@autoloads[name] = path 25 | autoload(name, path) 26 | end 27 | 28 | # This runs through the autoload list and explictly requires them for you. 29 | # Useful when running mail in a threaded process. 30 | # 31 | # Usage: 32 | # 33 | # require 'mail' 34 | # Mail.eager_autoload! 35 | def self.eager_autoload! 36 | @@autoloads.each { |_,path| require(path) } 37 | end 38 | 39 | # Autoload mail send and receive classes. 40 | require 'mail/network' 41 | 42 | require 'mail/message' 43 | require 'mail/part' 44 | require 'mail/header' 45 | require 'mail/parts_list' 46 | require 'mail/attachments_list' 47 | require 'mail/body' 48 | require 'mail/field' 49 | require 'mail/field_list' 50 | 51 | register_autoload :Envelope, 'mail/envelope' 52 | 53 | # Autoload header field elements and transfer encodings. 54 | require 'mail/elements' 55 | require 'mail/encodings' 56 | require 'mail/encodings/base64' 57 | require 'mail/encodings/quoted_printable' 58 | require 'mail/encodings/unix_to_unix' 59 | 60 | require 'mail/matchers/has_sent_mail' 61 | require 'mail/matchers/attachment_matchers' 62 | 63 | # Finally... require all the Mail.methods 64 | require 'mail/mail' 65 | end 66 | -------------------------------------------------------------------------------- /lib/mail/configuration.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | # 4 | # Thanks to Nicolas Fouché for this wrapper 5 | # 6 | require 'singleton' 7 | 8 | module Mail 9 | 10 | # The Configuration class is a Singleton used to hold the default 11 | # configuration for all Mail objects. 12 | # 13 | # Each new mail object gets a copy of these values at initialization 14 | # which can be overwritten on a per mail object basis. 15 | class Configuration 16 | include Singleton 17 | 18 | def initialize 19 | @delivery_method = nil 20 | @retriever_method = nil 21 | super 22 | end 23 | 24 | def delivery_method(method = nil, settings = {}) 25 | return @delivery_method if @delivery_method && method.nil? 26 | @delivery_method = lookup_delivery_method(method).new(settings) 27 | end 28 | 29 | def lookup_delivery_method(method) 30 | case method.is_a?(String) ? method.to_sym : method 31 | when nil 32 | Mail::SMTP 33 | when :smtp 34 | Mail::SMTP 35 | when :sendmail 36 | Mail::Sendmail 37 | when :exim 38 | Mail::Exim 39 | when :file 40 | Mail::FileDelivery 41 | when :smtp_connection 42 | Mail::SMTPConnection 43 | when :test 44 | Mail::TestMailer 45 | when :logger 46 | Mail::LoggerDelivery 47 | else 48 | method 49 | end 50 | end 51 | 52 | def retriever_method(method = nil, settings = {}) 53 | return @retriever_method if @retriever_method && method.nil? 54 | @retriever_method = lookup_retriever_method(method).new(settings) 55 | end 56 | 57 | def lookup_retriever_method(method) 58 | case method 59 | when nil 60 | Mail::POP3 61 | when :pop3 62 | Mail::POP3 63 | when :imap 64 | Mail::IMAP 65 | when :test 66 | Mail::TestRetriever 67 | else 68 | method 69 | end 70 | end 71 | 72 | def param_encode_language(value = nil) 73 | value ? @encode_language = value : @encode_language ||= 'en' 74 | end 75 | 76 | end 77 | 78 | end 79 | -------------------------------------------------------------------------------- /lib/mail/elements.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Mail 3 | register_autoload :Address, 'mail/elements/address' 4 | register_autoload :AddressList, 'mail/elements/address_list' 5 | register_autoload :ContentDispositionElement, 'mail/elements/content_disposition_element' 6 | register_autoload :ContentLocationElement, 'mail/elements/content_location_element' 7 | register_autoload :ContentTransferEncodingElement, 'mail/elements/content_transfer_encoding_element' 8 | register_autoload :ContentTypeElement, 'mail/elements/content_type_element' 9 | register_autoload :DateTimeElement, 'mail/elements/date_time_element' 10 | register_autoload :EnvelopeFromElement, 'mail/elements/envelope_from_element' 11 | register_autoload :MessageIdsElement, 'mail/elements/message_ids_element' 12 | register_autoload :MimeVersionElement, 'mail/elements/mime_version_element' 13 | register_autoload :PhraseList, 'mail/elements/phrase_list' 14 | register_autoload :ReceivedElement, 'mail/elements/received_element' 15 | end 16 | -------------------------------------------------------------------------------- /lib/mail/elements/address_list.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/address_lists_parser' 4 | 5 | module Mail 6 | class AddressList #:nodoc: 7 | attr_reader :addresses, :group_names 8 | 9 | # Mail::AddressList is the class that parses To, From and other address fields from 10 | # emails passed into Mail. 11 | # 12 | # AddressList provides a way to query the groups and mailbox lists of the passed in 13 | # string. 14 | # 15 | # It can supply all addresses in an array, or return each address as an address object. 16 | # 17 | # Mail::AddressList requires a correctly formatted group or mailbox list per RFC2822 or 18 | # RFC822. It also handles all obsolete versions in those RFCs. 19 | # 20 | # list = 'ada@test.lindsaar.net, My Group: mikel@test.lindsaar.net, Bob ;' 21 | # a = AddressList.new(list) 22 | # a.addresses #=> [# ["My Group"] 24 | def initialize(string) 25 | address_list = Parsers::AddressListsParser.parse(string) 26 | @addresses = address_list.addresses.map { |a| Address.new(a) } 27 | @group_names = address_list.group_names 28 | end 29 | 30 | def addresses_grouped_by_group 31 | addresses.select(&:group).group_by(&:group) 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/mail/elements/content_disposition_element.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/content_disposition_parser' 4 | 5 | module Mail 6 | class ContentDispositionElement #:nodoc: 7 | attr_reader :disposition_type, :parameters 8 | 9 | def initialize(string) 10 | content_disposition = Mail::Parsers::ContentDispositionParser.parse(cleaned(string)) 11 | @disposition_type = content_disposition.disposition_type 12 | @parameters = content_disposition.parameters 13 | end 14 | 15 | private 16 | def cleaned(string) 17 | string =~ /(.+);\s*$/ ? $1 : string 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/mail/elements/content_location_element.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/content_location_parser' 4 | 5 | module Mail 6 | class ContentLocationElement #:nodoc: 7 | attr_reader :location 8 | 9 | def initialize(string) 10 | @location = Mail::Parsers::ContentLocationParser.parse(string).location 11 | end 12 | 13 | def to_s(*args) 14 | location.to_s 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/mail/elements/content_transfer_encoding_element.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/content_transfer_encoding_parser' 4 | 5 | module Mail 6 | class ContentTransferEncodingElement #:nodoc: 7 | attr_reader :encoding 8 | 9 | def initialize(string) 10 | @encoding = Mail::Parsers::ContentTransferEncodingParser.parse(string).encoding 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/mail/elements/content_type_element.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/content_type_parser' 4 | 5 | module Mail 6 | class ContentTypeElement #:nodoc: 7 | attr_reader :main_type, :sub_type, :parameters 8 | 9 | def initialize(string) 10 | content_type = Mail::Parsers::ContentTypeParser.parse(cleaned(string)) 11 | @main_type = content_type.main_type 12 | @sub_type = content_type.sub_type 13 | @parameters = content_type.parameters 14 | end 15 | 16 | private 17 | def cleaned(string) 18 | if string =~ /;\s*$/ 19 | $` 20 | else 21 | string 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /lib/mail/elements/date_time_element.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/date_time_parser' 4 | 5 | module Mail 6 | class DateTimeElement #:nodoc: 7 | attr_reader :date_string, :time_string 8 | 9 | def initialize(string) 10 | date_time = Mail::Parsers::DateTimeParser.parse(string) 11 | @date_string = date_time.date_string 12 | @time_string = date_time.time_string 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/mail/elements/envelope_from_element.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/envelope_from_parser' 4 | require 'date' 5 | 6 | module Mail 7 | class EnvelopeFromElement #:nodoc: 8 | attr_reader :date_time, :address 9 | 10 | def initialize(string) 11 | envelope_from = Mail::Parsers::EnvelopeFromParser.parse(string) 12 | @address = envelope_from.address 13 | @date_time = ::DateTime.parse(envelope_from.ctime_date) if envelope_from.ctime_date 14 | end 15 | 16 | # RFC 4155: 17 | # a timestamp indicating the UTC date and time when the message 18 | # was originally received, conformant with the syntax of the 19 | # traditional UNIX 'ctime' output sans timezone (note that the 20 | # use of UTC precludes the need for a timezone indicator); 21 | def formatted_date_time 22 | if date_time 23 | if date_time.respond_to?(:ctime) 24 | date_time.ctime 25 | else 26 | date_time.strftime '%a %b %e %T %Y' 27 | end 28 | end 29 | end 30 | 31 | def to_s 32 | if date_time 33 | "#{address} #{formatted_date_time}" 34 | else 35 | address 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /lib/mail/elements/message_ids_element.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/message_ids_parser' 4 | require 'mail/utilities' 5 | 6 | module Mail 7 | class MessageIdsElement #:nodoc: 8 | def self.parse(string) 9 | new(string).tap(&:message_ids) 10 | end 11 | 12 | attr_reader :message_ids 13 | 14 | def initialize(string) 15 | @message_ids = parse(string) 16 | end 17 | 18 | def message_id 19 | message_ids.first 20 | end 21 | 22 | private 23 | def parse(string) 24 | if Utilities.blank? string 25 | [] 26 | else 27 | Mail::Parsers::MessageIdsParser.parse(string).message_ids 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/mail/elements/mime_version_element.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/mime_version_parser' 4 | 5 | module Mail 6 | class MimeVersionElement #:nodoc: 7 | attr_reader :major, :minor 8 | 9 | def initialize(string) 10 | mime_version = Mail::Parsers::MimeVersionParser.parse(string) 11 | @major = mime_version.major 12 | @minor = mime_version.minor 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/mail/elements/phrase_list.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/phrase_lists_parser' 4 | require 'mail/utilities' 5 | 6 | module Mail 7 | class PhraseList #:nodoc: 8 | attr_reader :phrases 9 | 10 | def initialize(string) 11 | @phrases = 12 | if Utilities.blank? string 13 | [] 14 | else 15 | Mail::Parsers::PhraseListsParser.parse(string).phrases.map { |p| Mail::Utilities.unquote(p) } 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /lib/mail/elements/received_element.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/parsers/received_parser' 4 | require 'mail/utilities' 5 | require 'date' 6 | 7 | module Mail 8 | class ReceivedElement #:nodoc: 9 | attr_reader :info, :date_time 10 | 11 | def initialize(string) 12 | if Utilities.blank? string 13 | @date_time = nil 14 | @info = nil 15 | else 16 | received = Mail::Parsers::ReceivedParser.parse(string) 17 | @date_time = datetime_for(received) 18 | @info = received.info 19 | end 20 | end 21 | 22 | def to_s(*args) 23 | "#{info}; #{date_time.to_s(*args)}" 24 | end 25 | 26 | private 27 | def datetime_for(received) 28 | ::DateTime.parse("#{received.date} #{received.time}") 29 | rescue ArgumentError => e 30 | raise e unless e.message == 'invalid date' 31 | warn "WARNING: Invalid date field for received element (#{received.date} #{received.time}): #{e.class}: #{e.message}" 32 | nil 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/mail/encodings/7bit.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/encodings/8bit' 4 | 5 | module Mail 6 | module Encodings 7 | # 7bit and 8bit are equivalent. 7bit encoding is for text only. 8 | class SevenBit < EightBit 9 | NAME = '7bit' 10 | PRIORITY = 1 11 | Encodings.register(NAME, self) 12 | 13 | def self.decode(str) 14 | ::Mail::Utilities.binary_unsafe_to_lf str 15 | end 16 | 17 | def self.encode(str) 18 | ::Mail::Utilities.binary_unsafe_to_crlf str 19 | end 20 | 21 | # Per RFC 2045 2.7. 7bit Data, No octets with decimal values greater than 127 are allowed. 22 | def self.compatible_input?(str) 23 | str.ascii_only? && super 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /lib/mail/encodings/8bit.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/encodings/binary' 4 | 5 | module Mail 6 | module Encodings 7 | class EightBit < Binary 8 | NAME = '8bit' 9 | PRIORITY = 4 10 | Encodings.register(NAME, self) 11 | 12 | # Per RFC 2821 4.5.3.1, SMTP lines may not be longer than 1000 octets including the . 13 | def self.compatible_input?(str) 14 | !str.lines.find { |line| line.bytesize > 998 } 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /lib/mail/encodings/base64.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/encodings/7bit' 4 | 5 | module Mail 6 | module Encodings 7 | # Base64 encoding handles binary content at the cost of 4 output bytes 8 | # per input byte. 9 | class Base64 < SevenBit 10 | NAME = 'base64' 11 | PRIORITY = 3 12 | Encodings.register(NAME, self) 13 | 14 | def self.can_encode?(enc) 15 | true 16 | end 17 | 18 | def self.decode(str) 19 | Utilities.decode_base64(str) 20 | end 21 | 22 | def self.encode(str) 23 | ::Mail::Utilities.binary_unsafe_to_crlf(Utilities.encode_base64(str)) 24 | end 25 | 26 | # 3 bytes in -> 4 bytes out 27 | def self.cost(str) 28 | 4.0 / 3 29 | end 30 | 31 | # Ruby Base64 inserts newlines automatically, so it doesn't exceed 32 | # SMTP line length limits. 33 | def self.compatible_input?(str) 34 | true 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /lib/mail/encodings/binary.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/encodings/identity' 4 | 5 | module Mail 6 | module Encodings 7 | class Binary < Identity 8 | NAME = 'binary' 9 | PRIORITY = 5 10 | Encodings.register(NAME, self) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /lib/mail/encodings/identity.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/encodings/transfer_encoding' 4 | 5 | module Mail 6 | module Encodings 7 | # Identity encodings do no encoding/decoding and have a fixed cost: 8 | # 1 byte in -> 1 byte out. 9 | class Identity < TransferEncoding #:nodoc: 10 | def self.decode(str) 11 | str 12 | end 13 | 14 | def self.encode(str) 15 | str 16 | end 17 | 18 | # 1 output byte per input byte. 19 | def self.cost(str) 20 | 1.0 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/mail/encodings/quoted_printable.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/encodings/7bit' 4 | 5 | module Mail 6 | module Encodings 7 | class QuotedPrintable < SevenBit 8 | NAME='quoted-printable' 9 | 10 | PRIORITY = 2 11 | 12 | def self.can_encode?(enc) 13 | EightBit.can_encode? enc 14 | end 15 | 16 | # Decode the string from Quoted-Printable. Cope with hard line breaks 17 | # that were incorrectly encoded as hex instead of literal CRLF. 18 | def self.decode(str) 19 | ::Mail::Utilities.to_lf ::Mail::Utilities.to_crlf(str).gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack1("M*") 20 | end 21 | 22 | def self.encode(str) 23 | ::Mail::Utilities.to_crlf [::Mail::Utilities.to_lf(str)].pack("M") 24 | end 25 | 26 | def self.cost(str) 27 | # These bytes probably do not need encoding 28 | c = str.count("\x9\xA\xD\x20-\x3C\x3E-\x7E") 29 | # Everything else turns into =XX where XX is a 30 | # two digit hex number (taking 3 bytes) 31 | total = (str.bytesize - c)*3 + c 32 | total.to_f/str.bytesize 33 | end 34 | 35 | # QP inserts newlines automatically and cannot violate the SMTP spec. 36 | def self.compatible_input?(str) 37 | true 38 | end 39 | 40 | private 41 | 42 | Encodings.register(NAME, self) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/mail/encodings/unix_to_unix.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Mail 3 | module Encodings 4 | class UnixToUnix < TransferEncoding 5 | NAME = "x-uuencode" 6 | 7 | def self.decode(str) 8 | str.sub(/\Abegin \d+ [^\n]*\n/, '').unpack1('u') 9 | end 10 | 11 | def self.encode(str) 12 | [str].pack("u") 13 | end 14 | 15 | Encodings.register(NAME, self) 16 | Encodings.register("uuencode", self) 17 | Encodings.register("x-uue", self) 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /lib/mail/envelope.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | # 4 | # = Mail Envelope 5 | # 6 | # The Envelope class provides a field for the first line in an 7 | # mbox file, that looks like "From mikel@test.lindsaar.net DATETIME" 8 | # 9 | # This envelope class reads that line, and turns it into an 10 | # Envelope.from and Envelope.date for your use. 11 | 12 | module Mail 13 | class Envelope < NamedStructuredField 14 | NAME = 'Envelope-From' 15 | 16 | def element 17 | @element ||= Mail::EnvelopeFromElement.new(value) 18 | end 19 | 20 | def from 21 | element.address 22 | end 23 | 24 | def date 25 | element.date_time 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/mail/fields/bcc_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Blind Carbon Copy Field 6 | # 7 | # The Bcc field inherits from StructuredField and handles the Bcc: header 8 | # field in the email. 9 | # 10 | # Sending bcc to a mail message will instantiate a Mail::Field object that 11 | # has a BccField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one Bcc field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.bcc = 'Mikel Lindsaar , ada@test.lindsaar.net' 21 | # mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 22 | # mail[:bcc] #=> '# '# '# '' # Bcc field does not get output into an email 27 | # mail[:bcc].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' 28 | # mail[:bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 29 | # mail[:bcc].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 30 | class BccField < CommonAddressField #:nodoc: 31 | NAME = 'Bcc' 32 | 33 | attr_accessor :include_in_headers 34 | 35 | def initialize(value = nil, charset = nil) 36 | super 37 | self.include_in_headers = false 38 | end 39 | 40 | # Bcc field should not be :encoded by default 41 | def encoded 42 | if include_in_headers 43 | super 44 | else 45 | '' 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /lib/mail/fields/cc_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Carbon Copy Field 6 | # 7 | # The Cc field inherits from StructuredField and handles the Cc: header 8 | # field in the email. 9 | # 10 | # Sending cc to a mail message will instantiate a Mail::Field object that 11 | # has a CcField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one Cc field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.cc = 'Mikel Lindsaar , ada@test.lindsaar.net' 21 | # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 22 | # mail[:cc] #=> '# '# '# 'Cc: Mikel Lindsaar , ada@test.lindsaar.net\r\n' 27 | # mail[:cc].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' 28 | # mail[:cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 29 | # mail[:cc].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 30 | class CcField < CommonAddressField #:nodoc: 31 | NAME = 'Cc' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/mail/fields/comments_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Comments Field 6 | # 7 | # The Comments field inherits from UnstructuredField and handles the Comments: 8 | # header field in the email. 9 | # 10 | # Sending comments to a mail message will instantiate a Mail::Field object that 11 | # has a CommentsField as its field type. 12 | # 13 | # An email header can have as many comments fields as it wants. There is no upper 14 | # limit, the comments field is also optional (that is, no comment is needed) 15 | # 16 | # == Examples: 17 | # 18 | # mail = Mail.new 19 | # mail.comments = 'This is a comment' 20 | # mail.comments #=> 'This is a comment' 21 | # mail[:comments] #=> '# '# '# ['This is a comment', "This is another comment"] 28 | class CommentsField < NamedUnstructuredField #:nodoc: 29 | NAME = 'Comments' 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /lib/mail/fields/common_date_field.rb: -------------------------------------------------------------------------------- 1 | require 'mail/utilities' 2 | 3 | module Mail 4 | class CommonDateField < NamedStructuredField #:nodoc: 5 | def self.singular? 6 | true 7 | end 8 | 9 | def self.normalize_datetime(string) 10 | if Utilities.blank?(string) 11 | datetime = ::DateTime.now 12 | else 13 | stripped = string.to_s.gsub(/\(.*?\)/, '').squeeze(' ') 14 | begin 15 | datetime = ::DateTime.parse(stripped) 16 | rescue ArgumentError => e 17 | raise unless 'invalid date' == e.message 18 | end 19 | end 20 | 21 | if datetime 22 | datetime.strftime('%a, %d %b %Y %H:%M:%S %z') 23 | else 24 | string 25 | end 26 | end 27 | 28 | def initialize(value = nil, charset = nil) 29 | super self.class.normalize_datetime(value), charset 30 | end 31 | 32 | # Returns a date time object of the parsed date 33 | def date_time 34 | ::DateTime.parse("#{element.date_string} #{element.time_string}") 35 | rescue ArgumentError => e 36 | raise e unless e.message == 'invalid date' 37 | end 38 | 39 | def default 40 | date_time 41 | end 42 | 43 | def element 44 | @element ||= Mail::DateTimeElement.new(value) 45 | end 46 | 47 | private 48 | def do_encode 49 | "#{name}: #{value}\r\n" 50 | end 51 | 52 | def do_decode 53 | value.to_s 54 | end 55 | end 56 | end 57 | -------------------------------------------------------------------------------- /lib/mail/fields/common_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/constants' 4 | 5 | module Mail 6 | class CommonField #:nodoc: 7 | def self.singular? 8 | false 9 | end 10 | 11 | def self.parse(*args) 12 | new(*args).tap(&:parse) 13 | end 14 | 15 | attr_accessor :name 16 | attr_reader :value 17 | attr_accessor :charset 18 | attr_reader :errors 19 | 20 | def initialize(name = nil, value = nil, charset = nil) 21 | @errors = [] 22 | 23 | self.name = name 24 | self.value = value 25 | self.charset = charset || 'utf-8' 26 | end 27 | 28 | def singular? 29 | self.class.singular? 30 | end 31 | 32 | def value=(value) 33 | @element = nil 34 | @value = value.is_a?(Array) ? value : value.to_s 35 | parse 36 | end 37 | 38 | def parse 39 | tap(&:element) 40 | end 41 | 42 | def element 43 | nil 44 | end 45 | 46 | def to_s 47 | decoded.to_s 48 | end 49 | 50 | def default 51 | decoded 52 | end 53 | 54 | def decoded 55 | do_decode 56 | end 57 | 58 | def encoded 59 | do_encode 60 | end 61 | 62 | def responsible_for?(field_name) 63 | name.to_s.casecmp(field_name.to_s) == 0 64 | end 65 | 66 | private 67 | 68 | FILENAME_RE = /\b(filename|name)=([^;"\r\n]+\s[^;"\r\n]+)/ 69 | def ensure_filename_quoted(value) 70 | if value.is_a?(String) 71 | value.sub FILENAME_RE, '\1="\2"' 72 | else 73 | value 74 | end 75 | end 76 | end 77 | end 78 | -------------------------------------------------------------------------------- /lib/mail/fields/common_message_id_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/utilities' 4 | 5 | module Mail 6 | class CommonMessageIdField < NamedStructuredField #:nodoc: 7 | def element 8 | @element ||= Mail::MessageIdsElement.new(value) 9 | end 10 | 11 | def message_id 12 | element.message_id 13 | end 14 | 15 | def message_ids 16 | element.message_ids 17 | end 18 | 19 | def default 20 | ids = message_ids 21 | ids.one? ? ids.first : ids 22 | end 23 | 24 | def to_s 25 | decoded.to_s 26 | end 27 | 28 | private 29 | def do_encode 30 | %Q{#{name}: #{formatted_message_ids("\r\n ")}\r\n} 31 | end 32 | 33 | def do_decode 34 | formatted_message_ids 35 | end 36 | 37 | def formatted_message_ids(join = ' ') 38 | message_ids.map { |m| "<#{m}>" }.join(join) if message_ids.any? 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /lib/mail/fields/content_description_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | class ContentDescriptionField < NamedUnstructuredField #:nodoc: 6 | NAME = 'Content-Description' 7 | 8 | def self.singular? 9 | true 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /lib/mail/fields/content_disposition_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | class ContentDispositionField < NamedStructuredField #:nodoc: 6 | NAME = 'Content-Disposition' 7 | 8 | def self.singular? 9 | true 10 | end 11 | 12 | def initialize(value = nil, charset = nil) 13 | super ensure_filename_quoted(value), charset 14 | end 15 | 16 | def element 17 | @element ||= Mail::ContentDispositionElement.new(value) 18 | end 19 | 20 | def disposition_type 21 | element.disposition_type 22 | end 23 | 24 | def parameters 25 | @parameters = ParameterHash.new 26 | element.parameters.each { |p| @parameters.merge!(p) } unless element.parameters.nil? 27 | @parameters 28 | end 29 | 30 | def filename 31 | @filename ||= parameters['filename'] || parameters['name'] 32 | end 33 | 34 | def encoded 35 | p = ";\r\n\s#{parameters.encoded}" if parameters.length > 0 36 | "#{name}: #{disposition_type}#{p}\r\n" 37 | end 38 | 39 | def decoded 40 | p = "; #{parameters.decoded}" if parameters.length > 0 41 | "#{disposition_type}#{p}" 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/mail/fields/content_id_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/utilities' 4 | 5 | module Mail 6 | class ContentIdField < NamedStructuredField #:nodoc: 7 | NAME = 'Content-ID' 8 | 9 | def self.singular? 10 | true 11 | end 12 | 13 | def initialize(value = nil, charset = nil) 14 | value = Mail::Utilities.generate_message_id if Utilities.blank?(value) 15 | super value, charset 16 | end 17 | 18 | def element 19 | @element ||= Mail::MessageIdsElement.new(value) 20 | end 21 | 22 | def content_id 23 | element.message_id 24 | end 25 | 26 | private 27 | def do_decode 28 | "<#{content_id}>" 29 | end 30 | 31 | def do_encode 32 | "#{name}: #{do_decode}\r\n" 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /lib/mail/fields/content_location_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | class ContentLocationField < NamedStructuredField #:nodoc: 6 | NAME = 'Content-Location' 7 | 8 | def self.singular? 9 | true 10 | end 11 | 12 | def element 13 | @element ||= Mail::ContentLocationElement.new(value) 14 | end 15 | 16 | def location 17 | element.location 18 | end 19 | 20 | def encoded 21 | "#{name}: #{location}\r\n" 22 | end 23 | 24 | def decoded 25 | location 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /lib/mail/fields/content_transfer_encoding_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | class ContentTransferEncodingField < NamedStructuredField #:nodoc: 6 | NAME = 'Content-Transfer-Encoding' 7 | 8 | def self.singular? 9 | true 10 | end 11 | 12 | def self.normalize_content_transfer_encoding(value) 13 | case value 14 | when /7-?bits?/i 15 | '7bit' 16 | when /8-?bits?/i 17 | '8bit' 18 | else 19 | value 20 | end 21 | end 22 | 23 | def initialize(value = nil, charset = nil) 24 | super self.class.normalize_content_transfer_encoding(value), charset 25 | end 26 | 27 | def element 28 | @element ||= Mail::ContentTransferEncodingElement.new(value) 29 | end 30 | 31 | def encoding 32 | element.encoding 33 | end 34 | 35 | private 36 | def do_encode 37 | "#{name}: #{encoding}\r\n" 38 | end 39 | 40 | def do_decode 41 | encoding 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/mail/fields/date_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Date Field 6 | # 7 | # The Date field inherits from StructuredField and handles the Date: header 8 | # field in the email. 9 | # 10 | # Sending date to a mail message will instantiate a Mail::Field object that 11 | # has a DateField as its field type. This includes all Mail::CommonAddress 12 | # module instance methods. 13 | # 14 | # There must be excatly one Date field in an RFC2822 email. 15 | # 16 | # == Examples: 17 | # 18 | # mail = Mail.new 19 | # mail.date = 'Mon, 24 Nov 1997 14:22:01 -0800' 20 | # mail.date #=> # 21 | # mail.date.to_s #=> 'Mon, 24 Nov 1997 14:22:01 -0800' 22 | # mail[:date] #=> '# '# '# ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 22 | # mail[:from] #=> '# '# '# 'from: Mikel Lindsaar , ada@test.lindsaar.net\r\n' 27 | # mail[:from].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' 28 | # mail[:from].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 29 | # mail[:from].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 30 | class FromField < CommonAddressField #:nodoc: 31 | NAME = 'From' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/mail/fields/in_reply_to_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = In-Reply-To Field 6 | # 7 | # The In-Reply-To field inherits from StructuredField and handles the 8 | # In-Reply-To: header field in the email. 9 | # 10 | # Sending in_reply_to to a mail message will instantiate a Mail::Field object that 11 | # has a InReplyToField as its field type. This includes all Mail::CommonMessageId 12 | # module instance metods. 13 | # 14 | # Note that, the #message_ids method will return an array of message IDs without the 15 | # enclosing angle brackets which per RFC are not syntactically part of the message id. 16 | # 17 | # Only one InReplyTo field can appear in a header, though it can have multiple 18 | # Message IDs. 19 | # 20 | # == Examples: 21 | # 22 | # mail = Mail.new 23 | # mail.in_reply_to = '' 24 | # mail.in_reply_to #=> '' 25 | # mail[:in_reply_to] #=> '# '# '# ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom'] 30 | class InReplyToField < CommonMessageIdField #:nodoc: 31 | NAME = 'In-Reply-To' 32 | 33 | def self.singular? 34 | true 35 | end 36 | 37 | def initialize(value = nil, charset = nil) 38 | if value.is_a?(Array) 39 | super value.join("\r\n\s"), charset 40 | else 41 | super 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/mail/fields/keywords_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # keywords = "Keywords:" phrase *("," phrase) CRLF 6 | class KeywordsField < NamedStructuredField #:nodoc: 7 | NAME = 'Keywords' 8 | 9 | def element 10 | @element ||= PhraseList.new(value) 11 | end 12 | 13 | def keywords 14 | element.phrases 15 | end 16 | 17 | def default 18 | keywords 19 | end 20 | 21 | private 22 | def do_decode 23 | keywords.join(', ') 24 | end 25 | 26 | def do_encode 27 | "#{name}: #{keywords.join(",\r\n ")}\r\n" 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /lib/mail/fields/message_id_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/utilities' 4 | 5 | module Mail 6 | # Only one Message-ID field may appear in a header. 7 | # 8 | # Note that parsed Message IDs do not contain their enclosing angle 9 | # brackets which, per RFC, are not part of the ID. 10 | # 11 | # mail = Mail.new 12 | # mail.message_id = '' 13 | # mail.message_id #=> '' 14 | # mail[:message_id] #=> '# '# '# 'F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom' 19 | # mail[:message_id].message_ids #=> ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom'] 20 | class MessageIdField < CommonMessageIdField #:nodoc: 21 | NAME = 'Message-ID' 22 | 23 | def self.singular? 24 | true 25 | end 26 | 27 | def initialize(value = nil, charset = nil) 28 | value = Mail::Utilities.generate_message_id if Utilities.blank?(value) 29 | super value, charset 30 | end 31 | 32 | def message_ids 33 | [message_id] 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /lib/mail/fields/mime_version_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/utilities' 4 | 5 | module Mail 6 | class MimeVersionField < NamedStructuredField #:nodoc: 7 | NAME = 'MIME-Version' 8 | 9 | def self.singular? 10 | true 11 | end 12 | 13 | def initialize(value = nil, charset = nil) 14 | value = '1.0' if Utilities.blank?(value) 15 | super value, charset 16 | end 17 | 18 | def element 19 | @element ||= Mail::MimeVersionElement.new(value) 20 | end 21 | 22 | def version 23 | "#{element.major}.#{element.minor}" 24 | end 25 | 26 | def major 27 | element.major.to_i 28 | end 29 | 30 | def minor 31 | element.minor.to_i 32 | end 33 | 34 | def encoded 35 | "#{name}: #{version}\r\n" 36 | end 37 | 38 | def decoded 39 | version 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /lib/mail/fields/named_structured_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | class NamedStructuredField < StructuredField #:nodoc: 6 | def initialize(value = nil, charset = nil) 7 | super self.class::NAME, value, charset 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/mail/fields/named_unstructured_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | class NamedUnstructuredField < UnstructuredField #:nodoc: 6 | def initialize(value = nil, charset = nil) 7 | super self.class::NAME, value, charset 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/mail/fields/optional_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # The field names of any optional-field MUST NOT be identical to any 6 | # field name specified elsewhere in this standard. 7 | # 8 | # optional-field = field-name ":" unstructured CRLF 9 | class OptionalField < UnstructuredField #:nodoc: 10 | private 11 | def do_encode 12 | "#{wrapped_value}\r\n" 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/mail/fields/parameter_hash.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'mail/constants' 4 | require 'mail/indifferent_hash' 5 | require 'mail/encodings' 6 | 7 | module Mail 8 | # ParameterHash is an intelligent Hash that allows you to add 9 | # parameter values including the MIME extension paramaters that 10 | # have the name*0="blah", name*1="bleh" keys, and will just return 11 | # a single key called name="blahbleh" and do any required un-encoding 12 | # to make that happen 13 | # 14 | # Parameters are defined in RFC2045. Split keys are in RFC2231. 15 | class ParameterHash < IndifferentHash #:nodoc: 16 | def [](key_name) 17 | key_pattern = Regexp.escape(key_name.to_s) 18 | pairs = [] 19 | exact = nil 20 | 21 | each do |k,v| 22 | if k =~ /^#{key_pattern}(\*|$)/i 23 | if $1 == Constants::ASTERISK 24 | pairs << [k, v] 25 | else 26 | exact = k 27 | end 28 | end 29 | end 30 | 31 | if pairs.empty? # Just dealing with a single value pair 32 | super(exact || key_name) 33 | else # Dealing with a multiple value pair or a single encoded value pair 34 | string = pairs.sort { |a,b| a.first.to_s <=> b.first.to_s }.map { |v| v.last }.join('') 35 | if mt = string.match(/([\w\-]+)?'(\w\w)?'(.*)/) 36 | string = mt[3] 37 | encoding = mt[1] 38 | else 39 | encoding = nil 40 | end 41 | Mail::Encodings.param_decode(string, encoding) 42 | end 43 | end 44 | 45 | def encoded 46 | map.sort_by { |a| a.first.to_s }.map! do |key_name, value| 47 | unless value.ascii_only? 48 | value = Mail::Encodings.param_encode(value) 49 | key_name = "#{key_name}*" 50 | end 51 | %Q{#{key_name}=#{Utilities.quote_token(value)}} 52 | end.join(";\r\n\s") 53 | end 54 | 55 | def decoded 56 | map.sort_by { |a| a.first.to_s }.map! do |key_name, value| 57 | %Q{#{key_name}=#{Utilities.quote_token(value)}} 58 | end.join("; ") 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/mail/fields/received_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # trace = [return] 6 | # 1*received 7 | # 8 | # return = "Return-Path:" path CRLF 9 | # 10 | # path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / 11 | # obs-path 12 | # 13 | # received = "Received:" name-val-list ";" date-time CRLF 14 | # 15 | # name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)] 16 | # 17 | # name-val-pair = item-name CFWS item-value 18 | # 19 | # item-name = ALPHA *(["-"] (ALPHA / DIGIT)) 20 | # 21 | # item-value = 1*angle-addr / addr-spec / 22 | # atom / domain / msg-id 23 | class ReceivedField < NamedStructuredField #:nodoc: 24 | NAME = 'Received' 25 | 26 | def element 27 | @element ||= Mail::ReceivedElement.new(value) 28 | end 29 | 30 | def date_time 31 | @datetime ||= element.date_time 32 | end 33 | 34 | def info 35 | element.info 36 | end 37 | 38 | def formatted_date 39 | if date_time.respond_to? :strftime and date_time.respond_to? :zone 40 | date_time.strftime("%a, %d %b %Y %H:%M:%S ") + date_time.zone.delete(':') 41 | end 42 | end 43 | 44 | private 45 | def do_encode 46 | if Utilities.blank?(value) 47 | "#{name}: \r\n" 48 | else 49 | "#{name}: #{info}; #{formatted_date}\r\n" 50 | end 51 | end 52 | 53 | def do_decode 54 | if Utilities.blank?(value) 55 | "" 56 | else 57 | "#{info}; #{formatted_date}" 58 | end 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/mail/fields/references_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = References Field 6 | # 7 | # The References field inherits references StructuredField and handles the References: header 8 | # field in the email. 9 | # 10 | # Sending references to a mail message will instantiate a Mail::Field object that 11 | # has a ReferencesField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Note that, the #message_ids method will return an array of message IDs without the 15 | # enclosing angle brackets which per RFC are not syntactically part of the message id. 16 | # 17 | # Only one References field can appear in a header, though it can have multiple 18 | # Message IDs. 19 | # 20 | # == Examples: 21 | # 22 | # mail = Mail.new 23 | # mail.references = '' 24 | # mail.references #=> '' 25 | # mail[:references] #=> '# '# '# ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom'] 30 | class ReferencesField < CommonMessageIdField #:nodoc: 31 | NAME = 'References' 32 | 33 | def self.singular? 34 | true 35 | end 36 | 37 | def initialize(value = nil, charset = nil) 38 | value = value.join("\r\n\s") if value.is_a?(Array) 39 | super value, charset 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /lib/mail/fields/reply_to_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Reply-To Field 6 | # 7 | # The Reply-To field inherits reply-to StructuredField and handles the Reply-To: header 8 | # field in the email. 9 | # 10 | # Sending reply_to to a mail message will instantiate a Mail::Field object that 11 | # has a ReplyToField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one Reply-To field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.reply_to = 'Mikel Lindsaar , ada@test.lindsaar.net' 21 | # mail.reply_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 22 | # mail[:reply_to] #=> '# '# '# 'Reply-To: Mikel Lindsaar , ada@test.lindsaar.net\r\n' 27 | # mail[:reply_to].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' 28 | # mail[:reply_to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 29 | # mail[:reply_to].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 30 | class ReplyToField < CommonAddressField #:nodoc: 31 | NAME = 'Reply-To' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/mail/fields/resent_bcc_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Resent-Bcc Field 6 | # 7 | # The Resent-Bcc field inherits resent-bcc StructuredField and handles the 8 | # Resent-Bcc: header field in the email. 9 | # 10 | # Sending resent_bcc to a mail message will instantiate a Mail::Field object that 11 | # has a ResentBccField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one Resent-Bcc field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.resent_bcc = 'Mikel Lindsaar , ada@test.lindsaar.net' 21 | # mail.resent_bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 22 | # mail[:resent_bcc] #=> '# '# '# 'Resent-Bcc: Mikel Lindsaar , ada@test.lindsaar.net\r\n' 27 | # mail[:resent_bcc].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' 28 | # mail[:resent_bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 29 | # mail[:resent_bcc].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 30 | class ResentBccField < CommonAddressField #:nodoc: 31 | NAME = 'Resent-Bcc' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/mail/fields/resent_cc_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Resent-Cc Field 6 | # 7 | # The Resent-Cc field inherits resent-cc StructuredField and handles the Resent-Cc: header 8 | # field in the email. 9 | # 10 | # Sending resent_cc to a mail message will instantiate a Mail::Field object that 11 | # has a ResentCcField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one Resent-Cc field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.resent_cc = 'Mikel Lindsaar , ada@test.lindsaar.net' 21 | # mail.resent_cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 22 | # mail[:resent_cc] #=> '# '# '# 'Resent-Cc: Mikel Lindsaar , ada@test.lindsaar.net\r\n' 27 | # mail[:resent_cc].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' 28 | # mail[:resent_cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 29 | # mail[:resent_cc].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 30 | class ResentCcField < CommonAddressField #:nodoc: 31 | NAME = 'Resent-Cc' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/mail/fields/resent_date_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # 6 | # resent-date = "Resent-Date:" date-time CRLF 7 | class ResentDateField < CommonDateField #:nodoc: 8 | NAME = 'Resent-Date' 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/mail/fields/resent_from_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Resent-From Field 6 | # 7 | # The Resent-From field inherits resent-from StructuredField and handles the Resent-From: header 8 | # field in the email. 9 | # 10 | # Sending resent_from to a mail message will instantiate a Mail::Field object that 11 | # has a ResentFromField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one Resent-From field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.resent_from = 'Mikel Lindsaar , ada@test.lindsaar.net' 21 | # mail.resent_from #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 22 | # mail[:resent_from] #=> '# '# '# 'Resent-From: Mikel Lindsaar , ada@test.lindsaar.net\r\n' 27 | # mail[:resent_from].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' 28 | # mail[:resent_from].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 29 | # mail[:resent_from].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 30 | class ResentFromField < CommonAddressField #:nodoc: 31 | NAME = 'Resent-From' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/mail/fields/resent_message_id_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # 6 | # resent-msg-id = "Resent-Message-ID:" msg-id CRLF 7 | class ResentMessageIdField < CommonMessageIdField #:nodoc: 8 | NAME = 'Resent-Message-ID' 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/mail/fields/resent_sender_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Resent-Sender Field 6 | # 7 | # The Resent-Sender field inherits resent-sender StructuredField and handles the Resent-Sender: header 8 | # field in the email. 9 | # 10 | # Sending resent_sender to a mail message will instantiate a Mail::Field object that 11 | # has a ResentSenderField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one Resent-Sender field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.resent_sender = 'Mikel Lindsaar , ada@test.lindsaar.net' 21 | # mail.resent_sender #=> ['mikel@test.lindsaar.net'] 22 | # mail[:resent_sender] #=> '# '# '# 'Mikel Lindsaar , ada@test.lindsaar.net' 27 | # mail.resent_sender.addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 28 | # mail.resent_sender.formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 29 | class ResentSenderField < CommonAddressField #:nodoc: 30 | NAME = 'Resent-Sender' 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /lib/mail/fields/resent_to_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Resent-To Field 6 | # 7 | # The Resent-To field inherits resent-to StructuredField and handles the Resent-To: header 8 | # field in the email. 9 | # 10 | # Sending resent_to to a mail message will instantiate a Mail::Field object that 11 | # has a ResentToField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one Resent-To field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.resent_to = 'Mikel Lindsaar , ada@test.lindsaar.net' 21 | # mail.resent_to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 22 | # mail[:resent_to] #=> '# '# '# 'Resent-To: Mikel Lindsaar , ada@test.lindsaar.net\r\n' 27 | # mail[:resent_to].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' 28 | # mail[:resent_to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 29 | # mail[:resent_to].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 30 | class ResentToField < CommonAddressField #:nodoc: 31 | NAME = 'Resent-To' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/mail/fields/return_path_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # 4.4.3. REPLY-TO / RESENT-REPLY-TO 6 | # 7 | # Note: The "Return-Path" field is added by the mail transport 8 | # service, at the time of final deliver. It is intended 9 | # to identify a path back to the orginator of the mes- 10 | # sage. The "Reply-To" field is added by the message 11 | # originator and is intended to direct replies. 12 | # 13 | # trace = [return] 14 | # 1*received 15 | # 16 | # return = "Return-Path:" path CRLF 17 | # 18 | # path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) / 19 | # obs-path 20 | # 21 | # received = "Received:" name-val-list ";" date-time CRLF 22 | # 23 | # name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)] 24 | # 25 | # name-val-pair = item-name CFWS item-value 26 | # 27 | # item-name = ALPHA *(["-"] (ALPHA / DIGIT)) 28 | # 29 | # item-value = 1*angle-addr / addr-spec / 30 | # atom / domain / msg-id 31 | # 32 | class ReturnPathField < CommonAddressField #:nodoc: 33 | NAME = 'Return-Path' 34 | 35 | def self.singular? 36 | true 37 | end 38 | 39 | def initialize(value = nil, charset = nil) 40 | if value == '<>' 41 | super nil, charset 42 | else 43 | super 44 | end 45 | end 46 | 47 | def default 48 | address 49 | end 50 | 51 | private 52 | def do_encode 53 | "#{name}: <#{address}>\r\n" 54 | end 55 | 56 | def do_decode 57 | address 58 | end 59 | end 60 | end 61 | -------------------------------------------------------------------------------- /lib/mail/fields/sender_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = Sender Field 6 | # 7 | # The Sender field inherits sender StructuredField and handles the Sender: header 8 | # field in the email. 9 | # 10 | # Sending sender to a mail message will instantiate a Mail::Field object that 11 | # has a SenderField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one Sender field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.sender = 'Mikel Lindsaar ' 21 | # mail.sender #=> 'mikel@test.lindsaar.net' 22 | # mail[:sender] #=> '# '# '# "Sender: Mikel Lindsaar \r\n" 27 | # mail[:sender].decoded #=> 'Mikel Lindsaar ' 28 | # mail[:sender].addresses #=> ['mikel@test.lindsaar.net'] 29 | # mail[:sender].formatted #=> ['Mikel Lindsaar '] 30 | class SenderField < CommonAddressField #:nodoc: 31 | NAME = 'Sender' 32 | 33 | def self.singular? 34 | true 35 | end 36 | 37 | def default 38 | address 39 | end 40 | 41 | def addresses 42 | Array(super.first) 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /lib/mail/fields/structured_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # Provides access to a structured header field 6 | # 7 | # ===Per RFC 2822: 8 | # 2.2.2. Structured Header Field Bodies 9 | # 10 | # Some field bodies in this standard have specific syntactical 11 | # structure more restrictive than the unstructured field bodies 12 | # described above. These are referred to as "structured" field bodies. 13 | # Structured field bodies are sequences of specific lexical tokens as 14 | # described in sections 3 and 4 of this standard. Many of these tokens 15 | # are allowed (according to their syntax) to be introduced or end with 16 | # comments (as described in section 3.2.3) as well as the space (SP, 17 | # ASCII value 32) and horizontal tab (HTAB, ASCII value 9) characters 18 | # (together known as the white space characters, WSP), and those WSP 19 | # characters are subject to header "folding" and "unfolding" as 20 | # described in section 2.2.3. Semantic analysis of structured field 21 | # bodies is given along with their syntax. 22 | class StructuredField < CommonField #:nodoc: 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/mail/fields/subject_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # 6 | # subject = "Subject:" unstructured CRLF 7 | class SubjectField < NamedUnstructuredField #:nodoc: 8 | NAME = 'Subject' 9 | 10 | def self.singular? 11 | true 12 | end 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /lib/mail/fields/to_field.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | # = To Field 6 | # 7 | # The To field inherits to StructuredField and handles the To: header 8 | # field in the email. 9 | # 10 | # Sending to to a mail message will instantiate a Mail::Field object that 11 | # has a ToField as its field type. This includes all Mail::CommonAddress 12 | # module instance metods. 13 | # 14 | # Only one To field can appear in a header, though it can have multiple 15 | # addresses and groups of addresses. 16 | # 17 | # == Examples: 18 | # 19 | # mail = Mail.new 20 | # mail.to = 'Mikel Lindsaar , ada@test.lindsaar.net' 21 | # mail.to #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 22 | # mail[:to] #=> '# '# '# 'To: Mikel Lindsaar , ada@test.lindsaar.net\r\n' 27 | # mail[:to].decoded #=> 'Mikel Lindsaar , ada@test.lindsaar.net' 28 | # mail[:to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net'] 29 | # mail[:to].formatted #=> ['Mikel Lindsaar ', 'ada@test.lindsaar.net'] 30 | class ToField < CommonAddressField #:nodoc: 31 | NAME = 'To' 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /lib/mail/matchers/attachment_matchers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Mail 3 | module Matchers 4 | def any_attachment 5 | AnyAttachmentMatcher.new 6 | end 7 | 8 | def an_attachment_with_filename(filename) 9 | AttachmentFilenameMatcher.new(filename) 10 | end 11 | 12 | def an_attachment_with_mime_type(filename) 13 | AttachmentMimeTypeMatcher.new(filename) 14 | end 15 | 16 | class AnyAttachmentMatcher 17 | def ===(other) 18 | other.attachment? 19 | end 20 | end 21 | 22 | class AttachmentFilenameMatcher 23 | attr_reader :filename 24 | def initialize(filename) 25 | @filename = filename 26 | end 27 | 28 | def ===(other) 29 | other.attachment? && other.filename == filename 30 | end 31 | end 32 | 33 | class AttachmentMimeTypeMatcher 34 | attr_reader :mime_type 35 | def initialize(mime_type) 36 | @mime_type = mime_type 37 | end 38 | 39 | def ===(other) 40 | other.attachment? && other.mime_type == mime_type 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/mail/multibyte/utils.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail #:nodoc: 5 | module Multibyte #:nodoc: 6 | # Returns a regular expression that matches valid characters in the current encoding 7 | def self.valid_character 8 | VALID_CHARACTER[Encoding.default_external.to_s] 9 | end 10 | 11 | # Returns true if string has valid utf-8 encoding 12 | def self.is_utf8?(string) 13 | case string.encoding 14 | when Encoding::UTF_8 15 | verify(string) 16 | when Encoding::ASCII_8BIT, Encoding::US_ASCII 17 | verify(to_utf8(string)) 18 | else 19 | false 20 | end 21 | end 22 | 23 | # Verifies the encoding of a string 24 | def self.verify(string) 25 | string.valid_encoding? 26 | end 27 | 28 | # Verifies the encoding of the string and raises an exception when it's not valid 29 | def self.verify!(string) 30 | raise EncodingError.new("Found characters with invalid encoding") unless verify(string) 31 | end 32 | 33 | # Removes all invalid characters from the string. 34 | # 35 | # Note: this method is a no-op in Ruby 1.9 36 | def self.clean(string) 37 | string 38 | end 39 | 40 | def self.to_utf8(string) 41 | string.dup.force_encoding(Encoding::UTF_8) 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/mail/network.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'mail/network/retriever_methods/base' 3 | 4 | module Mail 5 | register_autoload :SMTP, 'mail/network/delivery_methods/smtp' 6 | register_autoload :FileDelivery, 'mail/network/delivery_methods/file_delivery' 7 | register_autoload :LoggerDelivery, 'mail/network/delivery_methods/logger_delivery' 8 | register_autoload :Sendmail, 'mail/network/delivery_methods/sendmail' 9 | register_autoload :Exim, 'mail/network/delivery_methods/exim' 10 | register_autoload :SMTPConnection, 'mail/network/delivery_methods/smtp_connection' 11 | register_autoload :TestMailer, 'mail/network/delivery_methods/test_mailer' 12 | 13 | register_autoload :POP3, 'mail/network/retriever_methods/pop3' 14 | register_autoload :IMAP, 'mail/network/retriever_methods/imap' 15 | register_autoload :TestRetriever, 'mail/network/retriever_methods/test_retriever' 16 | end 17 | -------------------------------------------------------------------------------- /lib/mail/network/delivery_methods/exim.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Mail 4 | # A delivery method implementation which sends via exim. 5 | # 6 | # To use this, first find out where the exim binary is on your computer, 7 | # if you are on a mac or unix box, it is usually in /usr/sbin/exim, this will 8 | # be your exim location. 9 | # 10 | # Mail.defaults do 11 | # delivery_method :exim 12 | # end 13 | # 14 | # Or if your exim binary is not at '/usr/sbin/exim' 15 | # 16 | # Mail.defaults do 17 | # delivery_method :exim, :location => '/absolute/path/to/your/exim' 18 | # end 19 | # 20 | # Then just deliver the email as normal: 21 | # 22 | # Mail.deliver do 23 | # to 'mikel@test.lindsaar.net' 24 | # from 'ada@test.lindsaar.net' 25 | # subject 'testing exim' 26 | # body 'testing exim' 27 | # end 28 | # 29 | # Or by calling deliver on a Mail message 30 | # 31 | # mail = Mail.new do 32 | # to 'mikel@test.lindsaar.net' 33 | # from 'ada@test.lindsaar.net' 34 | # subject 'testing exim' 35 | # body 'testing exim' 36 | # end 37 | # 38 | # mail.deliver! 39 | class Exim < Sendmail 40 | DEFAULTS = { 41 | :location => '/usr/sbin/exim', 42 | :arguments => %w[ -i -t ] 43 | } 44 | 45 | # Uses -t option to extract recipients from the message. 46 | def destinations_for(envelope) 47 | nil 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /lib/mail/network/delivery_methods/file_delivery.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'mail/smtp_envelope' 3 | 4 | module Mail 5 | # FileDelivery class delivers emails into multiple files based on the destination 6 | # address. Each file is appended to if it already exists. 7 | # 8 | # So if you have an email going to fred@test, bob@test, joe@anothertest, and you 9 | # set your location path to /path/to/mails then FileDelivery will create the directory 10 | # if it does not exist, and put one copy of the email in three files, called 11 | # by their message id 12 | # 13 | # Make sure the path you specify with :location is writable by the Ruby process 14 | # running Mail. 15 | class FileDelivery 16 | require 'fileutils' 17 | 18 | attr_accessor :settings 19 | 20 | def initialize(values) 21 | self.settings = { :location => './mails', :extension => '' }.merge!(values) 22 | end 23 | 24 | def deliver!(mail) 25 | envelope = Mail::SmtpEnvelope.new(mail) 26 | 27 | if ::File.respond_to?(:makedirs) 28 | ::File.makedirs settings[:location] 29 | else 30 | ::FileUtils.mkdir_p settings[:location] 31 | end 32 | 33 | envelope.to.uniq.each do |to| 34 | path = ::File.join(settings[:location], File.basename(to.to_s+settings[:extension])) 35 | 36 | ::File.open(path, 'a') do |f| 37 | f.write envelope.message 38 | f.write "\r\n\r\n" 39 | end 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /lib/mail/network/delivery_methods/logger_delivery.rb: -------------------------------------------------------------------------------- 1 | require 'mail/smtp_envelope' 2 | 3 | module Mail 4 | class LoggerDelivery 5 | attr_reader :logger, :severity, :settings 6 | 7 | def initialize(settings) 8 | @settings = settings 9 | @logger = settings.fetch(:logger) { default_logger } 10 | @severity = derive_severity(settings[:severity]) 11 | end 12 | 13 | def deliver!(mail) 14 | logger.log(severity) { Mail::SmtpEnvelope.new(mail).message } 15 | end 16 | 17 | private 18 | def default_logger 19 | require 'logger' 20 | ::Logger.new($stdout) 21 | end 22 | 23 | def derive_severity(severity) 24 | case severity 25 | when nil 26 | Logger::INFO 27 | when Integer 28 | severity 29 | else 30 | Logger.const_get(severity.to_s.upcase) 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /lib/mail/network/delivery_methods/smtp_connection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'mail/smtp_envelope' 3 | 4 | module Mail 5 | # == Sending Email with SMTP 6 | # 7 | # Mail allows you to send emails using an open SMTP connection. This is done by 8 | # passing a created Net::SMTP object. This way we can get better performance to 9 | # our local mail server by reducing the number of connections at any one time. 10 | # 11 | # === Sending via SMTP server on Localhost 12 | # 13 | # To send mail open a connection with Net::Smtp using any options you like 14 | # === Delivering the email 15 | # 16 | # Once you have the settings right, sending the email is done by: 17 | # 18 | # smtp_conn = Net::SMTP.start(settings[:address], settings[:port]) 19 | # Mail.defaults do 20 | # delivery_method :smtp_connection, { :connection => smtp_conn } 21 | # end 22 | # 23 | # Mail.deliver do 24 | # to 'mikel@test.lindsaar.net' 25 | # from 'ada@test.lindsaar.net' 26 | # subject 'testing sendmail' 27 | # body 'testing sendmail' 28 | # end 29 | # 30 | # Or by calling deliver on a Mail message 31 | # 32 | # mail = Mail.new do 33 | # to 'mikel@test.lindsaar.net' 34 | # from 'ada@test.lindsaar.net' 35 | # subject 'testing sendmail' 36 | # body 'testing sendmail' 37 | # end 38 | # 39 | # mail.deliver! 40 | class SMTPConnection 41 | attr_accessor :smtp, :settings 42 | 43 | def initialize(values) 44 | raise ArgumentError.new('A Net::SMTP object is required for this delivery method') if values[:connection].nil? 45 | self.smtp = values[:connection] 46 | self.settings = values 47 | end 48 | 49 | # Send the message via SMTP. 50 | # The from and to attributes are optional. If not set, they are retrieve from the Message. 51 | def deliver!(mail) 52 | envelope = Mail::SmtpEnvelope.new(mail) 53 | response = smtp.sendmail(envelope.message, envelope.from, envelope.to) 54 | settings[:return_response] ? response : self 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/mail/network/delivery_methods/test_mailer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'mail/smtp_envelope' 3 | 4 | module Mail 5 | # The TestMailer is a bare bones mailer that does nothing. It is useful 6 | # when you are testing. 7 | # 8 | # It also provides a template of the minimum methods you require to implement 9 | # if you want to make a custom mailer for Mail 10 | class TestMailer 11 | # Provides a store of all the emails sent with the TestMailer so you can check them. 12 | def self.deliveries 13 | @@deliveries ||= [] 14 | end 15 | 16 | # Allows you to over write the default deliveries store from an array to some 17 | # other object. If you just want to clear the store, 18 | # call TestMailer.deliveries.clear. 19 | # 20 | # If you place another object here, please make sure it responds to: 21 | # 22 | # * << (message) 23 | # * clear 24 | # * length 25 | # * size 26 | # * and other common Array methods 27 | def self.deliveries=(val) 28 | @@deliveries = val 29 | end 30 | 31 | attr_accessor :settings 32 | 33 | def initialize(values) 34 | @settings = values.dup 35 | end 36 | 37 | def deliver!(mail) 38 | # Create the envelope to validate it 39 | Mail::SmtpEnvelope.new(mail) 40 | 41 | Mail::TestMailer.deliveries << mail 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /lib/mail/network/retriever_methods/test_retriever.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | 4 | module Mail 5 | 6 | class TestRetriever < Retriever 7 | 8 | def self.emails 9 | @@emails 10 | end 11 | 12 | def self.emails=(val) 13 | @@emails = val 14 | end 15 | 16 | def initialize(values) 17 | @@emails = [] 18 | end 19 | 20 | def find(options = nil, &block) 21 | options = options ? Hash[options] : {} 22 | options[:count] ||= :all 23 | options[:order] ||= :asc 24 | options[:what] ||= :first 25 | emails_index = (0...@@emails.size).to_a 26 | emails_index.reverse! if options[:what] == :last 27 | emails_index = case count = options[:count] 28 | when :all then emails_index 29 | when Integer then emails_index[0, count] 30 | else 31 | raise 'Invalid count option value: ' + count.inspect 32 | end 33 | if options[:what] == :last && options[:order] == :asc || options[:what] == :first && options[:order] == :desc 34 | emails_index.reverse! 35 | end 36 | emails_index.each { |idx| @@emails[idx].mark_for_delete = true } if options[:delete_after_find] 37 | emails = emails_index.map { |idx| @@emails[idx] } 38 | emails.each { |email| yield email } if block_given? 39 | @@emails.reject!(&:is_marked_for_delete?) if options[:delete_after_find] 40 | emails.size == 1 && options[:count] == 1 ? emails.first : emails 41 | end 42 | 43 | end 44 | 45 | end 46 | -------------------------------------------------------------------------------- /lib/mail/parser_tools.rb: -------------------------------------------------------------------------------- 1 | module Mail 2 | # Extends each field parser with utility methods. 3 | module ParserTools #:nodoc: 4 | # Slice bytes from ASCII-8BIT data and mark as UTF-8. 5 | if 'string'.respond_to?(:force_encoding) 6 | def chars(data, from_bytes, to_bytes) 7 | data.slice(from_bytes..to_bytes).force_encoding(Encoding::UTF_8) 8 | end 9 | else 10 | def chars(data, from_bytes, to_bytes) 11 | data.slice(from_bytes..to_bytes) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /lib/mail/parsers.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'mail/parsers/address_lists_parser' 4 | require 'mail/parsers/content_disposition_parser' 5 | require 'mail/parsers/content_location_parser' 6 | require 'mail/parsers/content_transfer_encoding_parser' 7 | require 'mail/parsers/content_type_parser' 8 | require 'mail/parsers/date_time_parser' 9 | require 'mail/parsers/envelope_from_parser' 10 | require 'mail/parsers/message_ids_parser' 11 | require 'mail/parsers/mime_version_parser' 12 | require 'mail/parsers/phrase_lists_parser' 13 | require 'mail/parsers/received_parser' 14 | -------------------------------------------------------------------------------- /lib/mail/parsers/content_transfer_encoding_parser.rl: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'mail/utilities' 3 | require 'mail/parser_tools' 4 | 5 | begin 6 | original_verbose, $VERBOSE = $VERBOSE, nil 7 | 8 | %%{ 9 | machine content_transfer_encoding; 10 | alphtype int; 11 | 12 | action encoding_s { encoding_s = p } 13 | action encoding_e { content_transfer_encoding.encoding = chars(data, encoding_s, p-1).downcase } 14 | 15 | # No-op actions 16 | action comment_e { } 17 | action comment_s { } 18 | action phrase_e { } 19 | action phrase_s { } 20 | action qstr_e { } 21 | action qstr_s { } 22 | action param_attr_e { } 23 | action param_attr_s { } 24 | action param_val_e { } 25 | action param_val_s { } 26 | action main_type_e { } 27 | action main_type_s { } 28 | action sub_type_e { } 29 | action sub_type_s { } 30 | 31 | include rfc2045_content_transfer_encoding "rfc2045_content_transfer_encoding.rl"; 32 | main := content_transfer_encoding; 33 | }%% 34 | 35 | module Mail::Parsers 36 | module ContentTransferEncodingParser 37 | extend Mail::ParserTools 38 | 39 | ContentTransferEncodingStruct = Struct.new(:encoding, :error) 40 | 41 | %%write data noprefix; 42 | 43 | def self.parse(data) 44 | data = data.dup.force_encoding(Encoding::ASCII_8BIT) if data.respond_to?(:force_encoding) 45 | 46 | content_transfer_encoding = ContentTransferEncodingStruct.new('') 47 | return content_transfer_encoding if Mail::Utilities.blank?(data) 48 | 49 | # Parser state 50 | encoding_s = nil 51 | 52 | # 5.1 Variables Used by Ragel 53 | p = 0 54 | eof = pe = data.length 55 | stack = [] 56 | 57 | %%write init; 58 | %%write exec; 59 | 60 | if false 61 | testEof 62 | end 63 | 64 | if p != eof || cs < %%{ write first_final; }%% 65 | raise Mail::Field::IncompleteParseError.new(Mail::ContentTransferEncodingElement, data, p) 66 | end 67 | 68 | content_transfer_encoding 69 | end 70 | end 71 | end 72 | 73 | ensure 74 | $VERBOSE = original_verbose 75 | end 76 | -------------------------------------------------------------------------------- /lib/mail/parsers/date_time_parser.rl: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'mail/utilities' 3 | require 'mail/parser_tools' 4 | 5 | begin 6 | original_verbose, $VERBOSE = $VERBOSE, nil 7 | 8 | %%{ 9 | machine date_time; 10 | alphtype int; 11 | 12 | # Date 13 | action date_s { date_s = p } 14 | action date_e { date_time.date_string = chars(data, date_s, p-1) } 15 | 16 | # Time 17 | action time_s { time_s = p } 18 | action time_e { date_time.time_string = chars(data, time_s, p-1) } 19 | 20 | # No-op actions 21 | action comment_s {} 22 | action comment_e {} 23 | action phrase_s {} 24 | action phrase_e {} 25 | action qstr_s {} 26 | action qstr_e {} 27 | 28 | include rfc5322_date_time "rfc5322_date_time.rl"; 29 | main := date_time; 30 | }%% 31 | 32 | module Mail::Parsers 33 | module DateTimeParser 34 | extend Mail::ParserTools 35 | 36 | DateTimeStruct = Struct.new(:date_string, :time_string, :error) 37 | 38 | %%write data noprefix; 39 | 40 | def self.parse(data) 41 | data = data.dup.force_encoding(Encoding::ASCII_8BIT) if data.respond_to?(:force_encoding) 42 | 43 | raise Mail::Field::NilParseError.new(Mail::DateTimeElement) if data.nil? 44 | 45 | date_time = DateTimeStruct.new([]) 46 | 47 | # Parser state 48 | date_s = time_s = nil 49 | 50 | # 5.1 Variables Used by Ragel 51 | p = 0 52 | eof = pe = data.length 53 | stack = [] 54 | 55 | %%write init; 56 | %%write exec; 57 | 58 | if false 59 | testEof 60 | end 61 | 62 | if p != eof || cs < %%{ write first_final; }%% 63 | raise Mail::Field::IncompleteParseError.new(Mail::DateTimeElement, data, p) 64 | end 65 | 66 | date_time 67 | end 68 | end 69 | end 70 | 71 | ensure 72 | $VERBOSE = original_verbose 73 | end 74 | -------------------------------------------------------------------------------- /lib/mail/parsers/mime_version_parser.rl: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'mail/utilities' 3 | require 'mail/parser_tools' 4 | 5 | begin 6 | original_verbose, $VERBOSE = $VERBOSE, nil 7 | 8 | %%{ 9 | machine mime_version; 10 | alphtype int; 11 | 12 | # Major Digits 13 | action major_digits_s { major_digits_s = p } 14 | action major_digits_e { mime_version.major = chars(data, major_digits_s, p-1) } 15 | 16 | # Minor Digits 17 | action minor_digits_s { minor_digits_s = p } 18 | action minor_digits_e { mime_version.minor = chars(data, minor_digits_s, p-1) } 19 | 20 | # No-op actions 21 | action comment_s {} 22 | action comment_e {} 23 | action qstr_s {} 24 | action qstr_e {} 25 | action phrase_s {} 26 | action phrase_e {} 27 | 28 | include rfc2045_mime "rfc2045_mime.rl"; 29 | main := mime_version; 30 | }%% 31 | 32 | module Mail::Parsers 33 | module MimeVersionParser 34 | extend Mail::ParserTools 35 | 36 | MimeVersionStruct = Struct.new(:major, :minor, :error) 37 | 38 | %%write data noprefix; 39 | 40 | def self.parse(data) 41 | data = data.dup.force_encoding(Encoding::ASCII_8BIT) if data.respond_to?(:force_encoding) 42 | 43 | return MimeVersionStruct.new('', nil) if Mail::Utilities.blank?(data) 44 | 45 | # Parser state 46 | mime_version = MimeVersionStruct.new 47 | major_digits_s = minor_digits_s = nil 48 | 49 | # 5.1 Variables Used by Ragel 50 | p = 0 51 | eof = pe = data.length 52 | stack = [] 53 | 54 | %%write init; 55 | %%write exec; 56 | 57 | if false 58 | testEof 59 | end 60 | 61 | if p != eof || cs < %%{ write first_final; }%% 62 | raise Mail::Field::IncompleteParseError.new(Mail::MimeVersionElement, data, p) 63 | end 64 | 65 | mime_version 66 | end 67 | end 68 | end 69 | 70 | ensure 71 | $VERBOSE = original_verbose 72 | end 73 | -------------------------------------------------------------------------------- /lib/mail/parsers/rfc2045_content_transfer_encoding.rl: -------------------------------------------------------------------------------- 1 | %%{ 2 | # RFC 2045 Section 6.1: Content-Transfer-Encoding Header Field 3 | # https://tools.ietf.org/html/rfc2045#section-6.1 4 | machine rfc2045_content_transfer_encoding; 5 | alphtype int; 6 | 7 | include rfc2045_content_type "rfc2045_content_type.rl"; 8 | 9 | encoding = ('7bits' | '8bits' | '7bit' | '8bit' | 'binary' | 10 | 'quoted-printable' | 'base64' | ietf_token | 11 | custom_x_token) >encoding_s %encoding_e; 12 | content_transfer_encoding = CFWS? encoding CFWS? ";"? CFWS?; 13 | }%% 14 | -------------------------------------------------------------------------------- /lib/mail/parsers/rfc2045_content_type.rl: -------------------------------------------------------------------------------- 1 | %%{ 2 | # RFC 2045 Section 5.1: Content-Type Header Field 3 | # https://tools.ietf.org/html/rfc2045#section-5.1 4 | # Previously: https://tools.ietf.org/html/rfc1049#section-3 5 | machine rfc2045_content_type; 6 | alphtype int; 7 | 8 | include rfc5322_lexical_tokens "rfc5322_lexical_tokens.rl"; 9 | 10 | token = 0x21..0x27 | 0x2a..0x2b | 0x2c..0x2e | 0x30..0x39 | 0x41..0x5a | 0x5e..0x7e; 11 | value = (quoted_string | (token -- '"' | 0x3d)+) >param_val_s %param_val_e; 12 | attribute = (token+) >param_attr_s %param_attr_e; 13 | parameter = CFWS? attribute "=" value CFWS?; 14 | 15 | ietf_token = token+; 16 | custom_x_token = 'x'i "-" token+; 17 | extension_token = ietf_token | custom_x_token; 18 | discrete_type = 'text'i | 'image'i | 'audio'i | 'video'i | 19 | 'application'i | extension_token; 20 | composite_type = 'message'i | 'multipart'i | extension_token; 21 | iana_token = token+; 22 | main_type = (discrete_type | composite_type) >main_type_s %main_type_e; 23 | sub_type = (extension_token | iana_token) >sub_type_s %sub_type_e; 24 | content_type = main_type "/" sub_type (((CFWS? ";"+) | CFWS) parameter CFWS?)*; 25 | }%% 26 | -------------------------------------------------------------------------------- /lib/mail/parsers/rfc2045_mime.rl: -------------------------------------------------------------------------------- 1 | %%{ 2 | # RFC 2045 MIME 3 | # https://tools.ietf.org/html/rfc2045 4 | machine rfc2045_mime; 5 | alphtype int; 6 | 7 | include rfc5322_lexical_tokens "rfc5322_lexical_tokens.rl"; 8 | 9 | # 4. MIME-Version Header Field 10 | # https://tools.ietf.org/html/rfc2045#section-4 11 | mime_version = CFWS? 12 | (DIGIT+ >major_digits_s %major_digits_e) 13 | comment? "." comment? 14 | (DIGIT+ >minor_digits_s %minor_digits_e) 15 | CFWS?; 16 | }%% 17 | -------------------------------------------------------------------------------- /lib/mail/parsers/rfc2183_content_disposition.rl: -------------------------------------------------------------------------------- 1 | %%{ 2 | # RFC 2183 The Content-Disposition Header Field 3 | # https://tools.ietf.org/html/rfc2183#section-2 4 | # 5 | # TODO: recognize filename, size, creation date, etc. 6 | machine rfc2183_content_disposition; 7 | alphtype int; 8 | 9 | include rfc2045_content_type "rfc2045_content_type.rl"; 10 | 11 | disposition_type = 'inline'i | 'attachment'i | extension_token; 12 | disposition_parm = parameter; 13 | disposition = (disposition_type >disp_type_s %disp_type_e) 14 | (";" disposition_parm)*; 15 | }%% 16 | -------------------------------------------------------------------------------- /lib/mail/parsers/rfc3629_utf8.rl: -------------------------------------------------------------------------------- 1 | %%{ 2 | # RFC 3629 4. Syntax of UTF-8 Byte Sequences 3 | # https://tools.ietf.org/html/rfc3629#section-4 4 | machine rfc3629_utf8; 5 | alphtype int; 6 | 7 | utf8_tail = 0x80..0xBF; 8 | 9 | utf8_2byte = 0xC2..0xDF utf8_tail; 10 | utf8_3byte = 0xE0 0xA0..0xBF utf8_tail | 11 | 0xE1..0xEC utf8_tail utf8_tail | 12 | 0xED 0x80..0x9F utf8_tail | 13 | 0xEE..0xEF utf8_tail utf8_tail; 14 | utf8_4byte = 0xF0 0x90..0xBF utf8_tail utf8_tail | 15 | 0xF1..0xF3 utf8_tail utf8_tail utf8_tail | 16 | 0xF4 0x80..0x8F utf8_tail utf8_tail; 17 | 18 | utf8_non_ascii = utf8_2byte | utf8_3byte | utf8_4byte; 19 | }%% 20 | -------------------------------------------------------------------------------- /lib/mail/parsers/rfc5234_abnf_core_rules.rl: -------------------------------------------------------------------------------- 1 | %%{ 2 | # RFC 5234 B.1. Core Rules 3 | # https://tools.ietf.org/html/rfc5234#appendix-B.1 4 | machine rfc5234_abnf_core_rules; 5 | alphtype int; 6 | 7 | include rfc3629_utf8 "rfc3629_utf8.rl"; 8 | 9 | LF = "\n"; 10 | CR = "\r"; 11 | CRLF = "\r\n"; 12 | SP = " "; 13 | HTAB = "\t"; 14 | WSP = SP | HTAB; 15 | DQUOTE = '"'; 16 | DIGIT = [0-9]; 17 | ALPHA = [a-zA-Z]; 18 | 19 | # RFC6532 extension for UTF-8 content 20 | rfc5234_VCHAR = 0x21..0x7e; 21 | VCHAR = rfc5234_VCHAR | utf8_non_ascii; 22 | }%% 23 | -------------------------------------------------------------------------------- /lib/mail/parsers/rfc5322_date_time.rl: -------------------------------------------------------------------------------- 1 | %%{ 2 | # RFC 5322 Internet Message Format 3 | # Section 3.3. Date and Time Specification 4 | # https://tools.ietf.org/html/rfc5322#section-3.3 5 | machine rfc5322_date_time; 6 | alphtype int; 7 | 8 | include rfc5322_lexical_tokens "rfc5322_lexical_tokens.rl"; 9 | 10 | # day_of_week 11 | day_name = "Mon" | "Tue" | "Wed" | "Thu" | "Fri" | "Sat" | "Sun"; 12 | obs_day_of_week = CFWS? day_name CFWS?; 13 | day_of_week = (FWS? day_name) | obs_day_of_week; 14 | 15 | # date 16 | obs_day = CFWS? (DIGIT | (DIGIT DIGIT)) CFWS?; 17 | day = (FWS? DIGIT DIGIT? FWS) | obs_day; 18 | month = "Jan" | "Feb" | "Mar" | "Apr" | "May" | "Jun" | "Jul" | "Aug" | "Sep" | "Oct" | "Nov" | "Dec"; 19 | obs_year = CFWS? (DIGIT DIGIT DIGIT*) CFWS?; 20 | year = FWS DIGIT DIGIT DIGIT DIGIT FWS | obs_year; 21 | date = day month year; 22 | 23 | # time 24 | obs_hour = CFWS? (DIGIT DIGIT) CFWS?; 25 | hour = DIGIT DIGIT | obs_hour; 26 | obs_minute = CFWS? (DIGIT DIGIT) CFWS?; 27 | minute = DIGIT DIGIT | obs_minute; 28 | obs_second = CFWS? (DIGIT DIGIT) CFWS?; 29 | second = DIGIT DIGIT | obs_second; 30 | obs_zone = "UT" | "GMT" | "EST" | "EDT" | "CST" | "CDT" | "MST" | "MDT" | "PST" | "PDT" | 0x41..0x49 | 0x4B..0x5A | 0x61..0x69 | 0x6B..0x7A; 31 | time_of_day = hour ":" minute (":" second)?; 32 | zone = FWS ((("+" | "-") DIGIT DIGIT DIGIT DIGIT) | obs_zone); 33 | time = time_of_day zone; 34 | 35 | date_time = (day_of_week ",")? 36 | (date >date_s %date_e) <: (time >time_s %time_e) CFWS?; 37 | }%% 38 | -------------------------------------------------------------------------------- /lib/mail/smtp_envelope.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Mail 4 | class SmtpEnvelope #:nodoc: 5 | # Reasonable cap on address length to avoid SMTP line length 6 | # overflow on old SMTP servers. 7 | MAX_ADDRESS_BYTESIZE = 2000 8 | 9 | attr_reader :from, :to, :message 10 | 11 | def initialize(mail) 12 | self.from = mail.smtp_envelope_from 13 | self.to = mail.smtp_envelope_to 14 | self.message = mail.encoded 15 | end 16 | 17 | def from=(addr) 18 | if Utilities.blank? addr 19 | raise ArgumentError, "SMTP From address may not be blank: #{addr.inspect}" 20 | end 21 | 22 | @from = validate_addr 'From', addr 23 | end 24 | 25 | def to=(addr) 26 | if Utilities.blank?(addr) 27 | raise ArgumentError, "SMTP To address may not be blank: #{addr.inspect}" 28 | end 29 | 30 | @to = Array(addr).map do |addr| 31 | validate_addr 'To', addr 32 | end 33 | end 34 | 35 | def message=(message) 36 | if Utilities.blank?(message) 37 | raise ArgumentError, 'SMTP message may not be blank' 38 | end 39 | 40 | @message = message 41 | end 42 | 43 | 44 | private 45 | def validate_addr(addr_name, addr) 46 | if addr.bytesize > MAX_ADDRESS_BYTESIZE 47 | raise ArgumentError, "SMTP #{addr_name} address may not exceed #{MAX_ADDRESS_BYTESIZE} bytes: #{addr.inspect}" 48 | end 49 | 50 | if /[\r\n]/.match?(addr) 51 | raise ArgumentError, "SMTP #{addr_name} address may not contain CR or LF line breaks: #{addr.inspect}" 52 | end 53 | 54 | addr 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/mail/values/unicode_tables.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/lib/mail/values/unicode_tables.dat -------------------------------------------------------------------------------- /lib/mail/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module Mail 3 | module VERSION 4 | 5 | MAJOR = 2 6 | MINOR = 9 7 | PATCH = 0 8 | BUILD = 'edge' 9 | 10 | STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.') 11 | 12 | def self.version 13 | STRING 14 | end 15 | 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /lib/mail/yaml.rb: -------------------------------------------------------------------------------- 1 | require 'yaml' 2 | 3 | module Mail 4 | module YAML 5 | def self.load(yaml) 6 | permitted_classes = [ 7 | Symbol, 8 | 9 | Mail::Body, 10 | 11 | # Delivery methods as listed in mail/configuration.rb 12 | Mail::SMTP, 13 | Mail::Sendmail, 14 | Mail::Exim, 15 | Mail::FileDelivery, 16 | Mail::SMTPConnection, 17 | Mail::TestMailer, 18 | Mail::LoggerDelivery, 19 | 20 | Mail.delivery_method.class, 21 | ] 22 | 23 | if Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0.pre1') 24 | ::YAML.safe_load(yaml, :permitted_classes => permitted_classes) 25 | else 26 | ::YAML.safe_load(yaml, permitted_classes) 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /mail.gemspec: -------------------------------------------------------------------------------- 1 | require_relative 'lib/mail/version' 2 | 3 | Gem::Specification.new do |s| 4 | s.name = "mail" 5 | s.version = Mail::VERSION::STRING 6 | s.author = "Mikel Lindsaar" 7 | s.email = "raasdnil@gmail.com" 8 | s.homepage = "https://github.com/mikel/mail" 9 | s.description = "A really Ruby Mail handler." 10 | s.summary = "Mail provides a nice Ruby DSL for making, sending and reading emails." 11 | s.license = "MIT" 12 | 13 | s.extra_rdoc_files = %w[ README.md ] 14 | s.rdoc_options << '--exclude' << 'lib/mail/values/unicode_tables.dat' 15 | 16 | s.required_ruby_version = ">= 2.5" 17 | 18 | s.add_dependency('logger') 19 | s.add_dependency('mini_mime', '>= 0.1.1') 20 | s.add_dependency('net-smtp') 21 | s.add_dependency('net-imap') 22 | s.add_dependency('net-pop') 23 | 24 | s.add_development_dependency('bundler', '>= 1.0.3') 25 | s.add_development_dependency('rake', '> 0.8.7') 26 | s.add_development_dependency('rspec', '~> 3.0') 27 | s.add_development_dependency('rspec-benchmark') 28 | s.add_development_dependency('rdoc') 29 | s.add_development_dependency('rufo') 30 | 31 | s.files = Dir.glob(%w[ README.md MIT-LICENSE lib/**/* ]) 32 | end 33 | -------------------------------------------------------------------------------- /rakelib/ragel.rake: -------------------------------------------------------------------------------- 1 | # RFC 6532 extensions rely on RFC 3629 UTF-8 chars 2 | rule 'lib/mail/parsers/rfc5234_abnf_core_rules.rl' => 'lib/mail/parsers/rfc3629_utf8.rl' 3 | 4 | # All RFC 5322 parsers depend on ABNF core rules 5 | rule %r|rfc5322_.+\.rl\z| => 'lib/mail/parsers/rfc5234_abnf_core_rules.rl' 6 | 7 | # RFC 5322 parser depends on its submodules 8 | file 'lib/mail/parsers/rfc5322.rl' => FileList['lib/mail/parsers/rfc5322_*.rl'] 9 | 10 | rule %r|_parser\.rl\z| => 'lib/mail/parsers/rfc5322.rl' 11 | 12 | # Ruby parsers depend on Ragel parser definitions 13 | # (remove -L to include line numbers for debugging) 14 | rule %r|_parser\.rb\z| => '%X.rl' do |t| 15 | sh "ragel -s -R -L -F1 -o #{t.name} #{t.source}" 16 | sh "bundle exec rufo --simple-exit #{t.name}" 17 | end 18 | 19 | # Dot files for Ragel parsers 20 | rule %r|_parser\.dot\z| => '%X.rl' do |t| 21 | sh "ragel -s -V -o #{t.name} #{t.source}" 22 | end 23 | 24 | rule %r|_parser\.svg\z| => '%X.dot' do |t| 25 | sh "dot -v -Tsvg -Goverlap=scale -o #{t.name} #{t.source}" 26 | end 27 | 28 | desc "Generate Ruby parsers from Ragel definitions" 29 | namespace :ragel do 30 | ragel_parsers = FileList['lib/mail/parsers/*_parser.rl'] 31 | task :generate => ragel_parsers.ext('.rb') 32 | task :svg => ragel_parsers.ext('.svg') 33 | end 34 | 35 | task :ragel => 'ragel:generate' 36 | -------------------------------------------------------------------------------- /spec/environment.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | $LOAD_PATH.unshift File.expand_path('../lib', __dir__) 3 | 4 | begin 5 | require 'byebug' 6 | rescue LoadError 7 | end 8 | 9 | require 'mail' 10 | 11 | if ENV['MBCHARS'] == 'activesupport' 12 | require 'active_support' 13 | Mail::Multibyte.proxy_class = ActiveSupport::Multibyte::Chars 14 | else 15 | require 'mail/multibyte/chars' 16 | Mail::Multibyte.proxy_class = Mail::Multibyte::Chars 17 | end 18 | -------------------------------------------------------------------------------- /spec/fixtures/attachments/basic_email.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: raasdnil@gmail.com 2 | Received: by 10.140.178.13 with SMTP id a13cs354079rvf; 3 | Fri, 21 Nov 2008 20:05:05 -0800 (PST) 4 | Received: by 10.151.44.15 with SMTP id w15mr2254748ybj.98.1227326704711; 5 | Fri, 21 Nov 2008 20:05:04 -0800 (PST) 6 | Return-Path: 7 | Received: from mail11.tpgi.com.au (mail11.tpgi.com.au [203.12.160.161]) 8 | by mx.google.com with ESMTP id 10si5117885gxk.81.2008.11.21.20.05.03; 9 | Fri, 21 Nov 2008 20:05:04 -0800 (PST) 10 | Received-SPF: neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) client-ip=203.12.160.161; 11 | Authentication-Results: mx.google.com; spf=neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) smtp.mail=test@lindsaar.net 12 | X-TPG-Junk-Status: Message not scanned 13 | X-TPG-Antivirus: Passed 14 | Received: from [192.0.0.253] (60-241-138-146.static.tpgi.com.au [60.0.0.146]) 15 | by mail11.tpgi.com.au (envelope-from test@lindsaar.net) (8.14.3/8.14.3) with ESMTP id mAM44xew022221 16 | for ; Sat, 22 Nov 2008 15:05:01 +1100 17 | Message-Id: <6B7EC235-5B17-4CA8-B2B8-39290DEB43A3@test.lindsaar.net> 18 | From: Mikel Lindsaar 19 | To: Mikel Lindsaar 20 | Content-Type: text/plain; charset=US-ASCII; format=flowed 21 | Content-Transfer-Encoding: 7bit 22 | MIME-Version: 1.0 (Apple Message framework v929.2) 23 | Subject: Testing 123 24 | Date: Sat, 22 Nov 2008 15:04:59 +1100 25 | X-Mailer: Apple Mail (2.929.2) 26 | 27 | Plain email. 28 | 29 | Hope it works well! 30 | 31 | Mikel 32 | -------------------------------------------------------------------------------- /spec/fixtures/attachments/test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/attachments/test.gif -------------------------------------------------------------------------------- /spec/fixtures/attachments/test.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/attachments/test.jpg -------------------------------------------------------------------------------- /spec/fixtures/attachments/test.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/attachments/test.pdf -------------------------------------------------------------------------------- /spec/fixtures/attachments/test.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/attachments/test.png -------------------------------------------------------------------------------- /spec/fixtures/attachments/test.tiff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/attachments/test.tiff -------------------------------------------------------------------------------- /spec/fixtures/attachments/test.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/attachments/test.zip -------------------------------------------------------------------------------- /spec/fixtures/attachments/てすと.txt: -------------------------------------------------------------------------------- 1 | this is a test 2 | これわてすと -------------------------------------------------------------------------------- /spec/fixtures/emails/.gitattributes: -------------------------------------------------------------------------------- 1 | # Never autoconvert line endings on fixture emails 2 | *.eml -text 3 | -------------------------------------------------------------------------------- /spec/fixtures/emails/attachment_emails/attachment_content_disposition.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 (Apple Message framework v730) 2 | Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 3 | Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> 4 | From: foo@example.com 5 | Subject: testing 6 | Date: Mon, 6 Jun 2005 22:21:22 +0200 7 | To: blah@example.com 8 | 9 | 10 | --Apple-Mail-13-196941151 11 | Content-Transfer-Encoding: quoted-printable 12 | Content-Type: text/plain; 13 | charset=ISO-8859-1; 14 | delsp=yes; 15 | format=flowed 16 | 17 | This is the first part. 18 | 19 | --Apple-Mail-13-196941151 20 | Content-Type: text/x-ruby-script; name="hello.rb" 21 | Content-Transfer-Encoding: 7bit 22 | Content-Disposition: attachment; 23 | filename="api.rb" 24 | 25 | puts "Hello, world!" 26 | gets 27 | 28 | --Apple-Mail-13-196941151-- 29 | 30 | -------------------------------------------------------------------------------- /spec/fixtures/emails/attachment_emails/attachment_content_location.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 (Apple Message framework v730) 2 | Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 3 | Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> 4 | From: foo@example.com 5 | Subject: testing 6 | Date: Mon, 6 Jun 2005 22:21:22 +0200 7 | To: blah@example.com 8 | 9 | 10 | --Apple-Mail-13-196941151 11 | Content-Transfer-Encoding: quoted-printable 12 | Content-Type: text/plain; 13 | charset=ISO-8859-1; 14 | delsp=yes; 15 | format=flowed 16 | 17 | This is the first part. 18 | 19 | --Apple-Mail-13-196941151 20 | Content-Type: image/jpeg 21 | Content-Transfer-Encoding: base64 22 | Content-Location: Photo25.jpg 23 | Content-ID: 24 | Content-Disposition: inline 25 | 26 | jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw 27 | ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE 28 | QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB 29 | gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5= 30 | 31 | --Apple-Mail-13-196941151-- 32 | 33 | -------------------------------------------------------------------------------- /spec/fixtures/emails/attachment_emails/attachment_nonascii_filename.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 (Apple Message framework v730) 2 | Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 3 | Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> 4 | From: foo@example.com 5 | Subject: testing 6 | Date: Mon, 6 Jun 2005 22:21:22 +0200 7 | To: blah@example.com 8 | 9 | 10 | --Apple-Mail-13-196941151 11 | Content-Transfer-Encoding: quoted-printable 12 | Content-Type: text/plain; 13 | charset=ISO-8859-1; 14 | delsp=yes; 15 | format=flowed 16 | 17 | This is the first part. 18 | 19 | --Apple-Mail-13-196941151 20 | Content-Type: text/plain; name=ciële.txt 21 | Content-Transfer-Encoding: 7bit 22 | Content-Disposition: attachment; 23 | filename=ciële.txt 24 | 25 | Hi there. 26 | 27 | --Apple-Mail-13-196941151-- 28 | 29 | -------------------------------------------------------------------------------- /spec/fixtures/emails/attachment_emails/attachment_only_email.eml: -------------------------------------------------------------------------------- 1 | Subject: this message JUST contains an attachment 2 | From: Ryan Finnie 3 | To: bob@domain.dom 4 | Content-Disposition: attachment; filename=blah.gz 5 | Content-Transfer-Encoding: base64 6 | Content-Description: Attachment has identical content to above foo.gz 7 | Message-Id: <1066974048.4264.62.camel@localhost> 8 | MIME-Version: 1.0 9 | Date: 23 Oct 2003 22:40:49 -0700 10 | Content-Type: application/x-gzip; NAME=blah.gz 11 | 12 | SubjectthismessageJUSTcontainsanattachmentFromRyanFinnierfinniedomaindomTobo 13 | bdomaindomContentDispositionattachmentfilenameAblahgzContentTypeapplication/ 14 | xgzipnameAblahgzContentTransferEncodingbase64ContentDescriptionAttachmenthas 15 | identicalcontenttoabovefoogzMessageId1066974048426462camellocalhostMimeVersi 16 | on10Date23Oct20032240490700H4sIAOHBmD8AA4vML1XPyVHISy1LLVJIy8xLUchNVeQCAHbe7 17 | 64WA -------------------------------------------------------------------------------- /spec/fixtures/emails/attachment_emails/attachment_with_base64_encoded_name.eml: -------------------------------------------------------------------------------- 1 | From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005 2 | Return-Path: 3 | Message-ID: 4 | Date: Sun, 8 May 2005 14:09:11 -0500 5 | From: xxxxxxxxx xxxxxxx 6 | Reply-To: xxxxxxxxx xxxxxxx 7 | To: xxxxx xxxx 8 | Subject: Fwd: Signed email causes file attachments 9 | In-Reply-To: 10 | MIME-Version: 1.0 11 | Content-Type: multipart/mixed; 12 | boundary="----=_Part_5028_7368284.1115579351471" 13 | References: 14 | 15 | ------=_Part_5028_7368284.1115579351471 16 | Content-Type: text/plain; charset=ISO-8859-1 17 | Content-Transfer-Encoding: quoted-printable 18 | Content-Disposition: inline 19 | 20 | We should not include these files or vcards as attachments. 21 | 22 | ---------- Forwarded message ---------- 23 | From: xxxxx xxxxxx 24 | Date: May 8, 2005 1:17 PM 25 | Subject: Signed email causes file attachments 26 | To: xxxxxxx@xxxxxxxxxx.com 27 | 28 | 29 | Hi, 30 | 31 | Test attachments with Base64 encoded filename. 32 | 33 | 34 | ------=_Part_5028_7368284.1115579351471 35 | Content-Type: application/pdf; name==?utf-8?B?VGhpcyBpcyBhIHRlc3QucGRm?= 36 | Content-Transfer-Encoding: base64 37 | Content-Disposition: attachment; filename==?utf-8?B?VGhpcyBpcyBhIHRlc3QucGRm?= 38 | 39 | MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w 40 | ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh 41 | d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt 42 | YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD 43 | ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t 44 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL 45 | 7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw 46 | ------=_Part_5028_7368284.1115579351471-- 47 | 48 | -------------------------------------------------------------------------------- /spec/fixtures/emails/attachment_emails/attachment_with_encoded_name.eml: -------------------------------------------------------------------------------- 1 | From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005 2 | Return-Path: 3 | Message-ID: 4 | Date: Sun, 8 May 2005 14:09:11 -0500 5 | From: xxxxxxxxx xxxxxxx 6 | Reply-To: xxxxxxxxx xxxxxxx 7 | To: xxxxx xxxx 8 | Subject: Fwd: Signed email causes file attachments 9 | In-Reply-To: 10 | MIME-Version: 1.0 11 | Content-Type: multipart/mixed; 12 | boundary="----=_Part_5028_7368284.1115579351471" 13 | References: 14 | 15 | ------=_Part_5028_7368284.1115579351471 16 | Content-Type: text/plain; charset=ISO-8859-1 17 | Content-Transfer-Encoding: quoted-printable 18 | Content-Disposition: inline 19 | 20 | We should not include these files or vcards as attachments. 21 | 22 | ---------- Forwarded message ---------- 23 | From: xxxxx xxxxxx 24 | Date: May 8, 2005 1:17 PM 25 | Subject: Signed email causes file attachments 26 | To: xxxxxxx@xxxxxxxxxx.com 27 | 28 | 29 | Hi, 30 | 31 | Test attachments oddly encoded with japanese charset. 32 | 33 | 34 | ------=_Part_5028_7368284.1115579351471 35 | Content-Type: application/octet-stream; name*=iso-2022-jp'ja'01%20Quien%20Te%20Dij%8aat.%20Pitbull.mp3 36 | Content-Transfer-Encoding: base64 37 | Content-Disposition: attachment 38 | 39 | MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w 40 | ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh 41 | d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt 42 | YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD 43 | ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t 44 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL 45 | 7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw 46 | ------=_Part_5028_7368284.1115579351471-- 47 | 48 | -------------------------------------------------------------------------------- /spec/fixtures/emails/attachment_emails/attachment_with_unquoted_name.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 (Apple Message framework v730) 2 | Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 3 | Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> 4 | From: foo@example.com 5 | Subject: testing 6 | Date: Mon, 6 Jun 2005 22:21:22 +0200 7 | To: blah@example.com 8 | 9 | 10 | --Apple-Mail-13-196941151 11 | Content-Transfer-Encoding: quoted-printable 12 | Content-Type: text/plain; 13 | charset=ISO-8859-1; 14 | delsp=yes; 15 | format=flowed 16 | 17 | This is the first part. 18 | 19 | --Apple-Mail-13-196941151 20 | Content-Type: text/plain; name=This is a test.txt 21 | Content-Transfer-Encoding: 7bit 22 | Content-Disposition: attachment; 23 | filename=This is a test.txt 24 | 25 | Hi there. 26 | 27 | --Apple-Mail-13-196941151-- 28 | 29 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/bad_date_header2.eml: -------------------------------------------------------------------------------- 1 | X-Message-Delivery: Vj0xLjE7dXM9MDtsPTA7YT0xO0Q9MTtTQ0w9MA== 2 | X-Message-Status: n 3 | X-SID-PRA: enews@Free-Quilting.com 4 | X-AUTH-Result: NONE 5 | X-Message-Info: JGTYoYF78jHCcITVD+zs6u3ahcolNfp0m61kNO2SBMwKZtwdSoGZLR+eV3xtqv3QU2mvP3b1AtESP6eCYbaI4dABkTSkMMCjZGPGH3Q01dsRSddQ0kCWDw== 6 | Received: from drg.drgnetwork.com ([63.76.155.39]) by col0-mc2-f14.Col0.hotmail.com with Microsoft SMTPSVC(6.0.3790.4675); 7 | Tue, 14 Dec 2010 22:59:10 -0800 8 | Received: from SFGAS1.DRGNETWORK.COM (sfgas1.drgnetwork.com [63.76.155.11]) 9 | by drg.drgnetwork.com (8.13.8/8.13.8) with ESMTP id oBF6xAuc018214 10 | for ; Wed, 15 Dec 2010 00:59:10 -0600 11 | Message-Id: <201012150659.oBF6xAuc018214@drg.drgnetwork.com> 12 | Sender: enews@Free-Quilting.com 13 | Date: Wed, 15 Dec 2010 59:10 -0500 14 | From: "Free-Quilting.com" 15 | MIME-Version: 1.0 16 | To: 17 | cc: 18 | Subject: 40% OFF holiday patterns and fabric! 19 | Content-Type: multipart/alternative; boundary="--PART.BOUNDARY.0001" 20 | Return-Path: bounces@strategicfulfillment.com 21 | X-OriginalArrivalTime: 15 Dec 2010 06:59:10.0647 (UTC) FILETIME=[93232C70:01CB9C25] 22 | 23 | 24 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/bad_encoded_subject.eml: -------------------------------------------------------------------------------- 1 | Subject: =?NONE?B?VEVTVA=?= 2 | 3 | TEST 4 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/cant_parse_from.eml: -------------------------------------------------------------------------------- 1 | Date: Thu, 11 Jun 2009 23:25:02 -0700 2 | From: Apple 3 | To: karl.baum@gmail.com 4 | Message-Id: <7oh6b1$1clhrjk@badger-vip.apple.com> 5 | Subject: Meet the new MacBook Pro family. Now includes 13-inch. 6 | MIME-Version: 1.0 7 | Content-Type: multipart/alternative; boundary=mimepart_4b0c353551675_3d1c15b79ea5e70c1783 8 | 9 | 10 | --mimepart_4b0c353551675_3d1c15b79ea5e70c1783 11 | Content-Type: text/plain; charset=ISO-8859-1 12 | Content-Transfer-Encoding: Quoted-printable 13 | Content-Disposition: inline 14 | 15 | From one solid piece of aluminum comes a MacBook Pro that's thin and light,= 16 | beautifully streamlined, and durable. 17 | 18 | --mimepart_4b0c353551675_3d1c15b79ea5e70c1783 19 | Content-Type: text/html; charset=ISO-8859-1 20 | Content-Transfer-Encoding: Quoted-printable 21 | Content-Disposition: inline 22 | 23 | 24 | 25 | 26 | 27 | From one solid piece of aluminum comes a MacBook Pro that's thin and light,= 28 | beautifully streamlined, and durable.
30 | 31 | 32 | --mimepart_4b0c353551675_3d1c15b79ea5e70c1783-- 33 | 34 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/content_transfer_encoding_qp_with_space.eml: -------------------------------------------------------------------------------- 1 | Return-Path: 2 | Delivered-To: em-ca-bait-precedes@em.ca 3 | Received: (qmail 7622 invoked by uid 115); 7 Nov 2004 21:30:59 -0000 4 | Received: from fyouizjnp@swissonline.ch by churchill by uid 64011 with qmail-scanner-1.22 5 | (clamdscan: 0.75-1. spamassassin: 2.63. Clear:RC:0(222.47.112.31):. 6 | Processed in 1.163709 secs); 07 Nov 2004 21:30:59 -0000 7 | Received: from unknown (HELO 209.5.178.248) (222.47.112.31) 8 | by churchill.factcomp.com with SMTP; 7 Nov 2004 21:30:57 -0000 9 | Message-ID: 10 | From: "Wilmer Capps" 11 | To: bait-passover@em.ca 12 | Subject: Low or High Blood Pressure? We can help. 13 | Date: Sun, 07 Nov 2004 18:23:56 -0300 14 | X-Mailer: gene annulus 15 | pneumococcus-polyhedral: belgrade hanoverian lima 16 | MIME-Version: 1.0 17 | Content-Type: multipart/alternative; 18 | boundary="----=_NextPart_000_003A_5008K66J.3Z4LC80J" 19 | 20 | This is a multi-part message in MIME format. 21 | 22 | ------=_NextPart_000_003A_5008K66J.3Z4LC80J 23 | Content-Type: text/plain; 24 | charset="iso-8859-1" 25 | Content-Transfer-Encoding: quoted printable 26 | 27 | If you're in need of a good RX site for online purchases, we are your answer. 28 | 29 | With Tens of Thousands of happy customers who saved huge, you can't go wrong. 30 | 31 | http://magyar8stator.com/26 Lots More Info Here 32 | 33 | Above URL is for more info & if you are interested. 34 | ------=_NextPart_000_003A_5008K66J.3Z4LC80J 35 | Content-Type: text/html; 36 | charset="iso-8859-1" 37 | Content-Transfer-Encoding: quoted-printable 38 | 39 | If you're in need of a good RX site for online purchases, we are your answ= 40 | er.
41 |
42 | With Tens of Thousands of happy customers who saved huge, you can't go wro= 43 | ng.
44 |
45 |
Lots More Info Here
46 |
47 |
48 | Above URL is for more info & if you are interested.
49 | 50 | 51 | 52 | 53 | ------=_NextPart_000_003A_5008K66J.3Z4LC80J-- 54 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/content_transfer_encoding_text-html.eml: -------------------------------------------------------------------------------- 1 | Return-Path: 2 | Delivered-To: rait@bruce-guenter.dyndns.org 3 | Received: (qmail 12977 invoked from network); 6 May 2005 10:58:40 -0000 4 | Received: from localhost (localhost [127.0.0.1]) 5 | by bruce-guenter.dyndns.org ([192.168.1.3]); 06 May 2005 10:58:40 -0000 6 | Received: from zak.futurequest.net ([127.0.0.1]) 7 | by localhost ([127.0.0.1]) 8 | with SMTP via TCP; 06 May 2005 10:58:40 -0000 9 | Received: (qmail 2252 invoked from network); 6 May 2005 10:58:39 -0000 10 | Received: from lsne-catv-dhcp-29-115.urbanet.ch (unknown [80.238.29.115]) 11 | by zak.futurequest.net ([69.5.6.152]) 12 | with SMTP via TCP; 06 May 2005 10:58:29 -0000 13 | Received: from mail.datavalet.com (80.238.29.115) 14 | by 80.238.29.115 (fairwayv.4) with SMTP 15 | id <09166i58p> 16 | (Authid: 3811297); Fri, 06 May 2005 10:52:01 -0100 17 | Reply-To: "chianfong cuthbert" 18 | From: "chianfong cuthbert" 19 | To: cvs@bruce-guenter.dyndns.org 20 | Cc: rait@bruce-guenter.dyndns.org 21 | Subject: Re: We will help you refinance your home. 22 | Date: Fri, 06 May 2005 15:55:01 +0400 23 | MIME-Version: 1.0 24 | Content-Type: multipart/alternative; 25 | boundary="--651790_269334.01570" 26 | Content-Length: 636 27 | Lines: 22 28 | 29 | ----651790_269334.01570 30 | Content-Type: text/html; 31 | charset="iso-8859-1" 32 | Content-Transfer-Encoding: text/html 33 | 34 | Hello,

35 | 36 | You have qualified for the lowest rate in years.
37 | You could get over $400,000 for as little as $500 a month.
38 | Low rates are fixed no matter what.

39 | 40 | Please visit the link below to verify your information:
41 | Approval Form

42 | 43 | Best Regards,
44 | chianfong cuthbert, Account Manager
45 | Reynolds Associates, LLC

46 |

47 | --------------------
48 | if you received this in error: re-m0-ve 49 | 50 | ----651790_269334.01570-- 51 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/encoding_madness.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: e-f5f4@app.ar-example.com 2 | Received: by 10.2.1.1 with SMTP id p21cs62610wem; 3 | Wed, 22 Sep 2010 00:30:55 -0700 (PDT) 4 | Received: by 10.15.2.1 with SMTP id p24mr499372ybh.380.1285140655013; 5 | Wed, 22 Sep 2010 00:30:55 -0700 (PDT) 6 | Return-Path: 7 | Received: from aquila.el-example.org ([174.1.8.2]) 8 | by mx.google.com with ESMTP id a6si11272839ybo.18.2010.09.22.00.30.54; 9 | Wed, 22 Sep 2010 00:30:54 -0700 (PDT) 10 | Received-SPF: neutral (google.com: 174.1.8.2 is neither permitted nor denied by best guess record for domain of production@aquila.el-example.org) client-ip=174.1.8.2; 11 | Authentication-Results: mx.google.com; spf=neutral (google.com: 174.1.8.2 is neither permitted nor denied by best guess record for domain of production@aquila.el-example.org) smtp.mail=production@aquila.el-example.org 12 | Received: from aquila.el-example.org (localhost [127.0.0.1]) 13 | by aquila.el-example.org (8.14.2/8.14.2) with ESMTP id o8M7UrfD018673 14 | for ; Wed, 22 Sep 2010 02:30:54 -0500 (CDT) 15 | (envelope-from production@aquila.el-example.org) 16 | Received: (from production@localhost) 17 | by aquila.el-example.org (8.14.2/8.14.2/Submit) id o8M7Urh3018672; 18 | Wed, 22 Sep 2010 02:30:53 -0500 (CDT) 19 | (envelope-from production) 20 | Message-Id: <201009220730.o8M7Urh3018672@aquila.el-example.org> 21 | MIME-Version: 1.0 22 | Content-Disposition: inline 23 | Content-Transfer-Encoding: quoted-printable 24 | Content-Type: text/plain 25 | X-Mailer: MIME::Lite 3.027 (F2.74; T1.28; A2.04; B3.07; Q3.07) 26 | Date: Wed, 22 Sep 2010 02:30:53 -0500 27 | From: no-reply@crm.el-example.org 28 | To: e-f5f4@app.ar-example.com 29 | Reply-To: "KLAUS- HÄNSCHEL" <> 30 | Subject: eBay Bid - 2008 Ford Super Duty F-350 DRW King Ranch Crew Cab 4x4 (156) - Stock# XXXX 31 | 32 | Body Text -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/header_fields_with_empty_values.eml: -------------------------------------------------------------------------------- 1 | Received: from mx01.medieveven.no (192.168.42.42) by epost.vartland.no 2 | (192.168.73.7) with Microsoft SMTP Server id 8.1.393.1; Fri, 30 Oct 2009 3 | 20:08:07 +0100 4 | Received: from woodward.joyent.us ([8.12.42.230]) by mx01.medieveven.no with 5 | ESMTP; 30 Oct 2009 20:11:23 +0100 6 | Received: from [10.0.0.5] (ti0083a340-0282.bb.online.no [88.89.59.28]) by 7 | woodward.joyent.us (Postfix) with ESMTPSA id EC35240C85 for 8 | ; Fri, 30 Oct 2009 19:07:44 +0000 (GMT) 9 | From: =?iso-8859-1?Q?J=F8rn_St=F8ylen?= 10 | To: AF Test 11 | Date: Fri, 30 Oct 2009 20:07:42 +0100 12 | Subject: Testmail 13 | Thread-Topic: Testmail 14 | Thread-Index: AcpZlFLF/Y9EfcC0QZKKEuUFm2Snqw== 15 | Message-ID: <4FDC124A-1FC4-4B29-8502-E459BD9AB397@prikkprikkprikk.no> 16 | Accept-Language: nb-NO 17 | X-MS-Exchange-Organization-AuthAs: Anonymous 18 | X-MS-Exchange-Organization-AuthSource: epost.vartland.no 19 | X-MS-Has-Attach: 20 | X-MS-TNEF-Correlator: 21 | x-ironport-anti-spam-filtered: true 22 | x-ironport-av: E=Sophos;i="4.44,655,1249250400"; d="scan'208";a="2439461" 23 | x-ironport-anti-spam-result: AvMBAPfV6koIDCrmhWdsb2JhbACbVgEBAQoLChoDxH2EPQQ 24 | Content-Type: text/plain; charset="iso-8859-1" 25 | Content-Transfer-Encoding: quoted-printable 26 | MIME-Version: 1.0 27 | 28 | 29 | 30 | -- 31 | J=F8rn St=F8ylen -- http://www.prikkprikkprikk.no 32 | 924 38 051 -- jorn@prikkprikkprikk.no 33 | 34 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/invalid_subject_characters.eml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/emails/error_emails/invalid_subject_characters.eml -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/missing_body.eml: -------------------------------------------------------------------------------- 1 | Message-ID: <001301c17797$9cd0ef30$a3ab620c@vaio> 2 | From: "SCS_2" 3 | To: 4 | Subject: REDACTED 5 | Date: Tue, 27 Nov 2001 15:02:35 -0800 6 | MIME-Version: 1.0 7 | Content-Type: multipart/mixed; 8 | boundary="----=_NextPart_000_000F_01C17754.8C3CAF30" 9 | X-Priority: 3 10 | X-MSMail-Priority: Normal 11 | X-Mailer: Microsoft Outlook Express 5.00.2919.6700 12 | X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6700 13 | Return-Path: redacted@attglobal.net 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/multiple_content_types.eml: -------------------------------------------------------------------------------- 1 | From: 2 | Subject: Redacted 3 | To: 4 | Message-ID: <105647271315.NCV17523@x263.net> 5 | MIME-version: 1.0 6 | Content-Type: multipart/alternative; boundary="----_001_5973_47T00ZN9.15SY2428" 7 | Content-type: text/plain 8 | 9 | This is a multi-part message in MIME format. 10 | 11 | ------_001_5973_47T00ZN9.15SY2428 12 | Content-Type: text/plain; 13 | charset="utf-8" 14 | Content-Transfer-Encoding: 7Bit 15 | 16 | foo 17 | 18 | ------_001_5973_47T00ZN9.15SY2428 19 | Content-Type: text/html; 20 | charset="utf-8" 21 | Content-Transfer-Encoding: 7Bit 22 | 23 |

foo

24 | 25 | ------_001_5973_47T00ZN9.15SY2428-- 26 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/multiple_invalid_content_dispositions.eml: -------------------------------------------------------------------------------- 1 | From: 2 | Subject: Redacted 3 | To: 4 | Message-ID: <105647271315.NCV17523@x263.net> 5 | MIME-version: 1.0 6 | Content-Type: text/html; 7 | charset=utf-8 8 | Content-Disposition: =?utf-8?Q?invalid?= 9 | Content-Transfer-Encoding: quoted-printable 10 | Content-Disposition: =?utf-8?Q?invalid?= 11 | 12 |

foo

13 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/multiple_references_with_one_invalid.eml: -------------------------------------------------------------------------------- 1 | From: 2 | Subject: Redacted 3 | To: 4 | Message-ID: <105647271315.NCV17523@x263.net> 5 | MIME-version: 1.0 6 | Content-Type: multipart/alternative; boundary="----_001_5973_47T00ZN9.15SY2428" 7 | References: 8 | References: , 10 | 11 | This is a multi-part message in MIME format. 12 | 13 | ------_001_5973_47T00ZN9.15SY2428 14 | Content-Type: text/plain; 15 | charset="utf-8" 16 | Content-Transfer-Encoding: 7Bit 17 | 18 | foo 19 | 20 | ------_001_5973_47T00ZN9.15SY2428 21 | Content-Type: text/html; 22 | charset="utf-8" 23 | Content-Transfer-Encoding: 7Bit 24 | 25 |

foo

26 | 27 | ------_001_5973_47T00ZN9.15SY2428-- 28 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/must_supply_encoding.eml: -------------------------------------------------------------------------------- 1 | X-YMAIL-UMID: 1_132725_AEe3iGIAAGS4TOAfWQ3foSiBC54 2 | X-Apparently-To: anyone@yahoo.com via 98.136.183.71; Sun, 14 Nov 2010 09:41:45 -0800 3 | Message-Id: <201011141741.oAEHfiKs020181@app9.msg2u.net> 4 | MIME-Version: 1.0 5 | Content-Transfer-Encoding: binary 6 | Content-Type: multipart/alternative; boundary="_----------=_128975650412616235" 7 | X-Mailer: MIME::Lite 3.020 (F2.73; T1.21; A1.77; B3.01; Q3.01) 8 | Date: Sun, 14 Nov 2010 17:41:44 +0000 9 | From: Biz Phone Systems from EclipseMediaOnline�� 10 | To: anyone@YAHOO.COM 11 | Subject: Impress your clients with a business phone��� 12 | Reply-To: Biz Phone Systems from EclipseMediaOnline�� <44.41.17.14.11.2010.1139.1.328.1477949.614@reply.here2there-travelers-msgs.net> 13 | 14 | -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/new_line_in_to_header.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: e-s-a-g-8718@app.ar.com 2 | Received: by 10.2.1.1 with SMTP id c60cs12954wel; 3 | Wed, 13 Oct 2010 07:44:39 -0700 (PDT) 4 | Received: by 10.15.1.1 with SMTP id f12mr1139775ybe.360.1286981078364; 5 | Wed, 13 Oct 2010 07:44:38 -0700 (PDT) 6 | Return-Path: 7 | Received: from services.travidiabamboo.com (services.travidiabamboo.com [72.21.1.1]) 8 | by mx.google.com with ESMTP id v33si16714378yba.88.2010.10.13.07.44.37; 9 | Wed, 13 Oct 2010 07:44:38 -0700 (PDT) 10 | Received-SPF: pass (google.com: domain of l@gcn-example.com designates 72.21.1.1 as permitted sender) client-ip=72.21.1.1; 11 | Authentication-Results: mx.google.com; spf=pass (google.com: domain of l@gcn-example.com designates 72.21.1.1 as permitted sender) smtp.mail=l@gcn-example.com 12 | Received: from travidiabamboo.com (services [10.0.0.2]) 13 | by services.travidiabamboo.com (Postfix) with ESMTP id A532170702; 14 | Wed, 13 Oct 2010 07:53:04 -0700 (PDT) 15 | Date: Wed, 13 Oct 2010 07:53:04 -0700 16 | From: l@gcn-example.com 17 | To: leads@sg.dc.com, 18 | sag@leads.gs.ry.com, 19 | sn@example-hotmail.com, 20 | e-s-a-g-8718@app.ar.com, 21 | jp@t-exmaple.com, 22 | 23 | cc@c-l-example.com 24 | Message-Id: <4cb5c7d0a3cce_120e..fdbed2b861958562@s.t-example.com.tmail> 25 | Subject: [Online Lead] Online Lead #1111111 26 | MIME-Version: 1.0 27 | Content-Type: text/plain; charset=utf-8 28 | 29 | 30 | 31 | 32 | 2010-10-13T07:53:04-09:00 33 | ... (not important) ... -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/trademark_character_in_subject.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: e-r-w-a-4462@app.ar.com 2 | Received: by 10.1.1.1 with SMTP id w10cs10896muo; 3 | Tue, 12 Oct 2010 13:20:24 -0700 (PDT) 4 | Received: by 10.2.1.5 with SMTP id bk15mr6105827qab.89.1286914824124; 5 | Tue, 12 Oct 2010 13:20:24 -0700 (PDT) 6 | Return-Path: 7 | Received: from mail.ga-example.com (mail.ga-example.com [64.1.2.3]) 8 | by mx.google.com with ESMTP id 13si112341247qcd.23.2010.10.12.13.20.23; 9 | Tue, 12 Oct 2010 13:20:24 -0700 (PDT) 10 | Received-SPF: neutral (google.com: 64.1.2.3 is neither permitted nor denied by best guess record for domain of j@yahoo-example.com) client-ip=64.1.2.3; 11 | Authentication-Results: mx.google.com; spf=neutral (google.com: 64.1.2.3 is neither permitted nor denied by best guess record for domain of j@yahoo-example.com) smtp.mail=j@yahoo-example.com 12 | X-MDAV-Processed: mail.ga-example.com, Tue, 12 Oct 2010 16:21:07 -0400 13 | X-Spam-Processed: mail.ga-example.com, Tue, 12 Oct 2010 16:21:06 -0400 14 | X-Spam-Checker-Version: SpamAssassin 3.2.5 (2008-06-10) on 15 | MAIL02.VD-example.com 16 | X-Spam-Level: 17 | X-Spam-Status: No, score=-1.1 required=5.0 tests=BAYES_00,DATE_IN_PAST_03_06, 18 | FORGED_YAHOO_RCVD,INVALID_DATE,NO_RELAYS,SUBJECT_NEEDS_ENCODING 19 | shortcircuit=no autolearn=no version=3.2.5 20 | Received: from GAWWW03 by ga-example.com (MDaemon PRO v11.0.3) 21 | with ESMTP id md50004804310.msg 22 | for ; Tue, 12 Oct 2010 16:21:05 -0400 23 | X-MDRemoteIP: 192.168.254.73 24 | X-Return-Path: j@yahoo-example.com 25 | X-Envelope-From: j@yahoo-example.com 26 | X-MDaemon-Deliver-To: e-r-w-a-4462@app.ar.com 27 | Date: Tue, 12 Oct 2010 16:21:05 H0500 28 | Subject: GA.comô has a lead for you 29 | To: c@ra-example.com,e-r-w-a-4462@app.ar.com,leads@ga-example.com 30 | MIME-Version: 1.0 31 | Content-type: text/plain; charset=iso-8859-1 32 | From: j@yahoo-example.com 33 | Message-ID: 34 | 35 | Body Text - not important -------------------------------------------------------------------------------- /spec/fixtures/emails/error_emails/weird_to_header.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: e-s-a-s-2200@app.ar.com 2 | Received: by 10.103.1.1 with SMTP id w10cs50835muo; 3 | Thu, 14 Oct 2010 20:25:16 -0700 (PDT) 4 | Received: by 10.150.205.4 with SMTP id c4mr736200ybg.26.1287113115711; 5 | Thu, 14 Oct 2010 20:25:15 -0700 (PDT) 6 | Return-Path: 7 | Received: from i.tp.host ([172.1.1.1]) 8 | by mx.google.com with ESMTP id s21si2123456.90.2010.10.14.20.25.15; 9 | Thu, 14 Oct 2010 20:25:15 -0700 (PDT) 10 | Received-SPF: neutral (google.com: 172.1.1.1 is neither permitted nor denied by best guess record for domain of anonymous@i.tp.host) client-ip=172.1.1.1; 11 | Authentication-Results: mx.google.com; spf=neutral (google.com: 172.1.1.1 is neither permitted nor denied by best guess record for domain of anonymous@i.tp.host) smtp.mail=anonymous@i.tp.host 12 | Received: (qmail 28454 invoked by uid 48); 14 Oct 2010 23:25:06 -0400 13 | Date: 14 Oct 2010 23:25:06 -0400 14 | Message-ID: <20101015032506.28448.qmail@i.tp.host> 15 | From: anonymous@i.tp.host 16 | To: , user-example@aol.com, e-s-a-s-2200@app.ar.com 17 | Subject: 18 | 19 | 20 | CONTACT: 21 | 22 | 23 | 24 | 25 | COMMENT: 26 | 27 | 28 | PAGE THEY WERE ON: 29 | 30 | -------------------------------------------------------------------------------- /spec/fixtures/emails/mime_emails/email_with_similar_boundaries.eml: -------------------------------------------------------------------------------- 1 | Received: from xxxx.xxxxxxx.xxx (127.0.0.1) by 2 | xxxx.xxxxxxxx.xxx (127.0.01) with Microsoft SMTP Server id 3 | 11.1.111.1; Thu, 5 Apr 2012 01:01:01 -0700 4 | Message-ID: 5 | To: 6 | Subject: Xxxxxx 7 | Date: Fri, 6 Apr 2012 01:01:01 +0000 8 | From: Xxxxx 9 | X-Mailer: PHP/5.2.6 10 | Content-Type: multipart/mixed; 11 | boundary="----=_NextPart_476c4fde88e507bb8028170e8cf47c73" 12 | MIME-Version: 1.0 13 | 14 | ------=_NextPart_476c4fde88e507bb8028170e8cf47c73 15 | Content-Type: multipart/alternative; 16 | boundary="----=_NextPart_476c4fde88e507bb8028170e8cf47c73_alt" 17 | 18 | ------=_NextPart_476c4fde88e507bb8028170e8cf47c73_alt 19 | Content-Type: text/plain; charset="utf-8" 20 | Content-Transfer-Encoding: 8bit 21 | 22 | Test 23 | 24 | ------=_NextPart_476c4fde88e507bb8028170e8cf47c73_alt 25 | Content-Type: text/html; charset="utf-8" 26 | Content-Transfer-Encoding: 8bit 27 | 28 | 29 | 30 | Test 31 | 32 |

Test

33 | 34 | 35 | ------=_NextPart_476c4fde88e507bb8028170e8cf47c73_alt-- 36 | 37 | ------=_NextPart_476c4fde88e507bb8028170e8cf47c73 38 | Content-Type: application/octetstream 39 | Content-Transfer-Encoding: base64 40 | Content-Disposition: attachment; filename="LOGO.png" 41 | Content-ID: 42 | 43 | SNIP 44 | 45 | ------=_NextPart_476c4fde88e507bb8028170e8cf47c73-- 46 | -------------------------------------------------------------------------------- /spec/fixtures/emails/mime_emails/raw_email11.eml: -------------------------------------------------------------------------------- 1 | From xxx@xxxx.com Wed Apr 27 14:15:31 2005 2 | MIME-Version: 1.0 (Apple Message framework v619.2) 3 | To: "xxxxx@xxxxx" 4 | Message-Id: <416eaebec6d333ec6939eaf8a7d80724@xxxxx> 5 | Content-Type: multipart/alternative; 6 | boundary=Apple-Mail-5-1037861608 7 | From: "xxxxx@xxxxx" 8 | Subject: worse when you use them. 9 | Date: Wed, 27 Apr 2005 14:15:31 -0700 10 | 11 | 12 | 13 | 14 | --Apple-Mail-5-1037861608 15 | Content-Transfer-Encoding: 7bit 16 | Content-Type: text/plain; 17 | charset=US-ASCII; 18 | format=flowed 19 | 20 | 21 | XXXXX Xxxxx 22 | 23 | --Apple-Mail-5-1037861608 24 | Content-Transfer-Encoding: 7bit 25 | Content-Type: text/enriched; 26 | charset=US-ASCII 27 | 28 | 29 | 30 | XXXXX Xxxxx 31 | 32 | 33 | --Apple-Mail-5-1037861608-- 34 | 35 | -------------------------------------------------------------------------------- /spec/fixtures/emails/mime_emails/raw_email12.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 (Apple Message framework v730) 2 | Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 3 | Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> 4 | From: foo@example.com 5 | Subject: testing 6 | Date: Mon, 6 Jun 2005 22:21:22 +0200 7 | To: blah@example.com 8 | 9 | 10 | --Apple-Mail-13-196941151 11 | Content-Transfer-Encoding: quoted-printable 12 | Content-Type: text/plain; 13 | charset=ISO-8859-1; 14 | delsp=yes; 15 | format=flowed 16 | 17 | This is the first part. 18 | 19 | --Apple-Mail-13-196941151 20 | Content-Type: image/jpeg 21 | Content-Transfer-Encoding: base64 22 | Content-Location: Photo25.jpg 23 | Content-ID: 24 | Content-Disposition: inline 25 | 26 | jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw 27 | ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE 28 | QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB 29 | gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5= 30 | 31 | --Apple-Mail-13-196941151-- 32 | 33 | -------------------------------------------------------------------------------- /spec/fixtures/emails/mime_emails/raw_email7.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 (Apple Message framework v730) 2 | Content-Type: multipart/mixed; boundary=Apple-Mail-13-196941151 3 | Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> 4 | From: foo@example.com 5 | Subject: testing 6 | Date: Mon, 6 Jun 2005 22:21:22 +0200 7 | To: blah@example.com 8 | 9 | 10 | --Apple-Mail-13-196941151 11 | Content-Type: multipart/mixed; 12 | boundary=Apple-Mail-12-196940926 13 | 14 | 15 | --Apple-Mail-12-196940926 16 | Content-Transfer-Encoding: quoted-printable 17 | Content-Type: text/plain; 18 | charset=ISO-8859-1; 19 | delsp=yes; 20 | format=flowed 21 | 22 | This is the first part. 23 | 24 | --Apple-Mail-12-196940926 25 | Content-Transfer-Encoding: 7bit 26 | Content-Type: text/x-ruby-script; 27 | x-unix-mode=0666; 28 | name="test.rb" 29 | Content-Disposition: attachment; 30 | filename=test.rb 31 | 32 | puts "testing, testing" 33 | 34 | --Apple-Mail-12-196940926 35 | Content-Transfer-Encoding: base64 36 | Content-Type: application/pdf; 37 | x-unix-mode=0666; 38 | name="test.pdf" 39 | Content-Disposition: inline; 40 | filename=test.pdf 41 | 42 | YmxhaCBibGFoIGJsYWg= 43 | 44 | --Apple-Mail-12-196940926 45 | Content-Transfer-Encoding: 7bit 46 | Content-Type: text/plain; 47 | charset=US-ASCII; 48 | format=flowed 49 | 50 | 51 | 52 | --Apple-Mail-12-196940926-- 53 | 54 | --Apple-Mail-13-196941151 55 | Content-Transfer-Encoding: base64 56 | Content-Type: application/pkcs7-signature; 57 | name=smime.p7s 58 | Content-Disposition: attachment; 59 | filename=smime.p7s 60 | 61 | jamisSqGSIb3DQEHAqCAMIjamisxCzAJBgUrDgMCGgUAMIAGCSqGSjamisEHAQAAoIIFSjCCBUYw 62 | ggQujamisQICBD++ukQwDQYJKojamisNAQEFBQAwMTELMAkGA1UEBhMCRjamisAKBgNVBAoTA1RE 63 | QzEUMBIGjamisxMLVERDIE9DRVMgQ0jamisNMDQwMjI5MTE1OTAxWhcNMDYwMjamisIyOTAxWjCB 64 | gDELMAkGA1UEjamisEsxKTAnBgNVBAoTIEjamisuIG9yZ2FuaXNhdG9yaXNrIHRpbjamisRuaW5= 65 | 66 | --Apple-Mail-13-196941151-- 67 | -------------------------------------------------------------------------------- /spec/fixtures/emails/mime_emails/raw_email_encoded_stack_level_too_deep.eml: -------------------------------------------------------------------------------- 1 | X-Gmail-Received: 220984aec4c4885e060987be043c9363cbef8551 2 | Received: by 10.36.47.16; Tue, 28 Jun 2005 01:02:11 -0700 (PDT) 3 | Message-ID: <89d7557c0506280102495d555f@mail.gmail.com> 4 | Date: Tue, 28 Jun 2005 01:02:11 -0700 5 | From: Gmail Team 6 | Reply-To: x.y@gmail.com 7 | To: =?ISO-8859-1?Q?Nicolas_Fouch=E9?= 8 | Subject: =?ISO-8859-1?Q?Nicolas_Fouch=E9_has_accepted_your_invitation_to_Gmail?= 9 | MIME-Version: 1.0 10 | Content-Type: multipart/alternative; 11 | boundary="----=_Part_976_15222032.1119945731186" 12 | 13 | ------=_Part_976_15222032.1119945731186 14 | Content-Type: text/plain; charset=ISO-8859-1 15 | Content-Transfer-Encoding: quoted-printable 16 | Content-Disposition: inline 17 | 18 | Nicolas Fouch=E9 has accepted your invitation to Gmail and has chosen the= 19 | =20 20 | brand new address x.y@gmail.com. Be one of the first to email Nicolas= 21 | =20 22 | at this new Gmail address--just hit reply and send Nicolas a message.=20 23 | x.y@gmail.com has also been automatically added to your contact list= 24 | =20 25 | so you can stay in touch with Gmail.=20 26 | 27 | 28 | Thanks,=20 29 | 30 | The Gmail Team 31 | 32 | ------=_Part_976_15222032.1119945731186 33 | Content-Type: text/html; charset=ISO-8859-1 34 | Content-Transfer-Encoding: quoted-printable 35 | Content-Disposition: inline 36 | 37 | 38 | 39 |

Nicolas Fouch=E9 has accepted your invitation to Gmail and has 40 | chosen the brand new address x.y@gmail.com. Be one of the first to = 41 | email=20 42 | Nicolas at this new Gmail address--just hit reply and send=20 43 | Nicolas a message. x.y@gmail.com has also been automatically added = 44 | to 45 | your contact list so you can stay in touch with Gmail. 46 |

47 |


48 | Thanks,

49 |

The Gmail Team

50 |
51 | 52 | 53 | ------=_Part_976_15222032.1119945731186-- -------------------------------------------------------------------------------- /spec/fixtures/emails/mime_emails/raw_email_with_binary_encoded.eml: -------------------------------------------------------------------------------- 1 | From email_test@me.nowhere 2 | Return-Path: 3 | Received: from omta05sl.mx.bigpond.com by me.nowhere.else with ESMTP id 632BD5758 for ; Sun, 21 Oct 2007 19:38:21 +1000 4 | Received: from oaamta05sl.mx.bigpond.com by omta05sl.mx.bigpond.com with ESMTP id <20071021093820.HSPC16667.omta05sl.mx.bigpond.com@oaamta05sl.mx.bigpond.com> for ; Sun, 21 Oct 2007 19:38:20 +1000 5 | Received: from mikel091a by oaamta05sl.mx.bigpond.com with SMTP id <20071021093820.JFMT24025.oaamta05sl.mx.bigpond.com@mikel091a> for ; Sun, 21 Oct 2007 19:38:20 +1000 6 | Date: Sun, 21 Oct 2007 19:38:13 +1000 7 | From: Mikel Lindsaar 8 | Reply-To: Mikel Lindsaar 9 | To: mikel@me.nowhere 10 | Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a> 11 | Subject: Testing outlook 12 | Subject: Another PDF 13 | MIME-Version: 1.0 14 | Content-Type: multipart/alternative; 15 | boundary=----=_Part_13069834_15179892.1376435426074 16 | 17 | 18 | ------=_Part_13069834_15179892.1376435426074 19 | Content-Type: image/jpeg; name=2013-08-13_19-08-28-1.jpg 20 | Content-Transfer-Encoding: binary 21 | Content-Location: 2013-08-13_19-08-28-1.jpg 22 | 23 | BINARY_CONTENT_GOES_HERE 24 | ------=_Part_13069834_15179892.1376435426074-- 25 | -------------------------------------------------------------------------------- /spec/fixtures/emails/mime_emails/sig_only_email.eml: -------------------------------------------------------------------------------- 1 | Date: Mon, 4 Jun 2007 15:01:31 -0700 2 | From: Test 3 | To: Mikel 4 | Subject: Re: Testing multipart/signed 5 | Message-ID: <20070604150131.40d4fa1e@reforged> 6 | MIME-Version: 1.0 7 | Content-Type: multipart/signed; boundary=Sig_2GIY2xfzqSADMmu9sKGJqWm; 8 | protocol="application/pgp-signature"; micalg=PGP-SHA1 9 | 10 | --Sig_2GIY2xfzqSADMmu9sKGJqWm 11 | Content-Type: text/plain; charset=US-ASCII 12 | Content-Transfer-Encoding: quoted-printable 13 | 14 | This is random text, not what has been signed below, ie, this sig 15 | email is not signed correctly. 16 | 17 | --Sig_2GIY2xfzqSADMmu9sKGJqWm 18 | Content-Type: application/pgp-signature; name=signature.asc 19 | Content-Disposition: attachment; filename=signature.asc 20 | 21 | -----BEGIN PGP SIGNATURE----- 22 | Version: GnuPG v1.4.6 (GNU/Linux) 23 | 24 | iD8DB1111Iu7dfRchrkBInkRArniAKCue17JOxXBiAZHwLy3uFacU+pmhwCgwzhf 25 | V5YSPv2xmYOA6mJ6oVaasseQ= 26 | =T7p9 27 | -----END PGP SIGNATURE----- 28 | 29 | --Sig_2GIY2xfzqSADMmu9sKGJqWm-- 30 | -------------------------------------------------------------------------------- /spec/fixtures/emails/mime_emails/two_from_in_message.eml: -------------------------------------------------------------------------------- 1 | Return-Path: 2 | Received: from mail-xxx.google.com (mail-xxx.google.com [0.0.0.0]) 3 | by smtp.test.com (Postfix) with ESMTP id xxxx 4 | for ; Wed, 2 Dec 2009 09:39:57 +0000 (UTC) 5 | Received: by qyk6 with SMTP id 6so3112qyk.3 6 | for ; Wed, 02 Dec 2009 01:39:53 -0800 (PST) 7 | MIME-Version: 1.0 8 | Received: by 0.0.0.0 with SMTP id xxx.000.0000000000000; Wed, 9 | 02 Dec 2009 01:39:53 -0800 (PST) 10 | In-Reply-To: <8fc5086d0912020131y377ba0ccpf8f14783cfc3014a@test.com> 11 | References: <8fc5086d0912020131y377ba0ccpf8f14783cfc3014a@test.com> 12 | From: Tester 1 13 | Date: Wed, 2 Dec 2009 22:39:33 +1300 14 | Message-ID: <8fc5086d0912020139y1564ad32jb4f4209fa464f4a6@test.com> 15 | Subject: Sending messages include last little bit 16 | To: tester2@test.com 17 | Content-Type: multipart/alternative; boundary=00c09fa216eb1bfc0a0479bba823 18 | 19 | --00c09fa216eb1bfc0a0479bba823 20 | Content-Type: text/plain; charset=ISO-8859-1 21 | 22 | When sending email: 23 | * From Hotmail you get the ads as well. 24 | * From GMail you also get the person's signature. 25 | 26 | I'm curious, and I might do some digging tomorrow as well, to see if its 27 | possible to strip the last little bit (signature/ads) from email messages. 28 | 29 | --00c09fa216eb1bfc0a0479bba823 30 | Content-Type: text/html; charset=ISO-8859-1 31 | Content-Transfer-Encoding: quoted-printable 32 | 33 |
When sending ema= 34 | il:
* From Hotmail you get the ads as well.
* Fr= 35 | om GMail you also get the person's signature.

= 36 | I'm curious, and I might do some digging tomorrow as well, to see if it= 37 | s possible to strip the last little bit (signature/ads) from email messages= 38 | .
39 | 40 |
41 | 42 | --00c09fa216eb1bfc0a0479bba823-- -------------------------------------------------------------------------------- /spec/fixtures/emails/multi_charset/japanese.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 2 | Subject: =?UTF-8?B?44G+44G/44KA44KB44KC?= 3 | From: Mikel Lindsaar 4 | To: =?UTF-8?B?44G/44GR44KL?= 5 | Content-Type: text/plain; charset=UTF-8 6 | Content-Transfer-Encoding: base64 7 | 8 | 44GL44GN44GP44GI44GTCgotLSAKaHR0cDovL2xpbmRzYWFyLm5ldC8KUmFpbHMsIFJTcGVjIGFu 9 | ZCBMaWZlIGJsb2cuLi4uCg== -------------------------------------------------------------------------------- /spec/fixtures/emails/multi_charset/japanese_attachment.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 2 | Received: by 10.231.35.72 with HTTP; Fri, 16 Oct 2009 05:39:34 -0700 (PDT) 3 | Date: Fri, 16 Oct 2009 23:39:34 +1100 4 | Delivered-To: raasdnil@gmail.com 5 | Message-ID: <57a815bf0910160539m64240421gb35ea52e101aedbc@mail.gmail.com> 6 | Subject: testing 7 | From: Mikel Lindsaar 8 | To: Mikel Lindsaar 9 | Content-Type: multipart/mixed; boundary=00032557395e3572cf04760cb060 10 | 11 | --00032557395e3572cf04760cb060 12 | Content-Type: text/plain; charset=UTF-8 13 | 14 | testing 15 | 16 | -- 17 | http://lindsaar.net/ 18 | Rails, RSpec and Life blog.... 19 | 20 | --00032557395e3572cf04760cb060 21 | Content-Type: text/plain; charset=UTF-8; name="=?UTF-8?B?44Gm44GZ44GoLnR4dA==?=" 22 | Content-Disposition: attachment; filename="=?UTF-8?B?44Gm44GZ44GoLnR4dA==?=" 23 | Content-Transfer-Encoding: base64 24 | X-Attachment-Id: f_g0uxfl510 25 | 26 | dGhpcyBpcyBhIHRlc3QK44GT44KM44KP44Gm44GZ44Go 27 | --00032557395e3572cf04760cb060-- -------------------------------------------------------------------------------- /spec/fixtures/emails/multi_charset/japanese_iso_2022.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 2 | Subject: =?UTF-8?B?44G+44G/44KA44KB44KC?= 3 | From: Mikel Lindsaar 4 | To: =?UTF-8?B?44G/44GR44KL?= 5 | Content-Type: text/plain; 6 | charset=iso-2022-jp 7 | Content-Transfer-Encoding: 7bit 8 | 9 | $B$9$_$^$;$s!#(B 10 | 11 | -------------------------------------------------------------------------------- /spec/fixtures/emails/multi_charset/japanese_shift_jis.eml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/emails/multi_charset/japanese_shift_jis.eml -------------------------------------------------------------------------------- /spec/fixtures/emails/multi_charset/ks_c_5601-1987.eml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/emails/multi_charset/ks_c_5601-1987.eml -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/basic_email.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: raasdnil@gmail.com 2 | Received: by 10.140.178.13 with SMTP id a13cs354079rvf; 3 | Fri, 21 Nov 2008 20:05:05 -0800 (PST) 4 | Received: by 10.151.44.15 with SMTP id w15mr2254748ybj.98.1227326704711; 5 | Fri, 21 Nov 2008 20:05:04 -0800 (PST) 6 | Return-Path: 7 | Received: from mail11.tpgi.com.au (mail11.tpgi.com.au [203.12.160.161]) 8 | by mx.google.com with ESMTP id 10si5117885gxk.81.2008.11.21.20.05.03; 9 | Fri, 21 Nov 2008 20:05:04 -0800 (PST) 10 | Received-SPF: neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) client-ip=203.12.160.161; 11 | Authentication-Results: mx.google.com; spf=neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) smtp.mail=test@lindsaar.net 12 | X-TPG-Junk-Status: Message not scanned 13 | X-TPG-Antivirus: Passed 14 | Received: from [192.0.0.253] (60-241-138-146.static.tpgi.com.au [60.0.0.146]) 15 | by mail11.tpgi.com.au (envelope-from test@lindsaar.net) (8.14.3/8.14.3) with ESMTP id mAM44xew022221 16 | for ; Sat, 22 Nov 2008 15:05:01 +1100 17 | Message-Id: <6B7EC235-5B17-4CA8-B2B8-39290DEB43A3@test.lindsaar.net> 18 | From: Mikel Lindsaar 19 | To: Mikel Lindsaar 20 | Content-Type: text/plain; charset=US-ASCII; format=flowed 21 | Content-Transfer-Encoding: 7bit 22 | MIME-Version: 1.0 (Apple Message framework v929.2) 23 | Subject: Testing 123 24 | Date: Sat, 22 Nov 2008 15:04:59 +1100 25 | X-Mailer: Apple Mail (2.929.2) 26 | 27 | Plain email. 28 | 29 | Hope it works well! 30 | 31 | Mikel 32 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/basic_email_lf.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: raasdnil@gmail.com 2 | Received: by 10.140.178.13 with SMTP id a13cs354079rvf; 3 | Fri, 21 Nov 2008 20:05:05 -0800 (PST) 4 | Received: by 10.151.44.15 with SMTP id w15mr2254748ybj.98.1227326704711; 5 | Fri, 21 Nov 2008 20:05:04 -0800 (PST) 6 | Return-Path: 7 | Received: from mail11.tpgi.com.au (mail11.tpgi.com.au [203.12.160.161]) 8 | by mx.google.com with ESMTP id 10si5117885gxk.81.2008.11.21.20.05.03; 9 | Fri, 21 Nov 2008 20:05:04 -0800 (PST) 10 | Received-SPF: neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) client-ip=203.12.160.161; 11 | Authentication-Results: mx.google.com; spf=neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) smtp.mail=test@lindsaar.net 12 | X-TPG-Junk-Status: Message not scanned 13 | X-TPG-Antivirus: Passed 14 | Received: from [192.0.0.253] (60-241-138-146.static.tpgi.com.au [60.0.0.146]) 15 | by mail11.tpgi.com.au (envelope-from test@lindsaar.net) (8.14.3/8.14.3) with ESMTP id mAM44xew022221 16 | for ; Sat, 22 Nov 2008 15:05:01 +1100 17 | Message-Id: <6B7EC235-5B17-4CA8-B2B8-39290DEB43A3@test.lindsaar.net> 18 | From: Mikel Lindsaar 19 | To: Mikel Lindsaar 20 | Content-Type: text/plain; charset=US-ASCII; format=flowed 21 | Content-Transfer-Encoding: 7bit 22 | MIME-Version: 1.0 (Apple Message framework v929.2) 23 | Subject: Testing 123 24 | Date: Sat, 22 Nov 2008 15:04:59 +1100 25 | X-Mailer: Apple Mail (2.929.2) 26 | 27 | Plain email. 28 | 29 | Hope it works well! 30 | 31 | Mikel 32 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/mix_caps_content_type.eml: -------------------------------------------------------------------------------- 1 | From joe@company.com Fri Feb 19 08:41:30 2010 2 | From: Big Bug bb@bug.com 3 | To: rubymail@ruby-lang.org 4 | Subject: undef method parameter bug 5 | Date: Fri, 19 Feb 2010 10:08:29 +0300 6 | MIME-Version: 1.0 7 | Content-Type: Text/Plain; charset="iso-8859-1" 8 | Content-Transfer-Encoding: quoted-printable 9 | Message-Id: 201002191008.30117.foo.bar@company.com 10 | 11 | foo bar 12 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email.eml: -------------------------------------------------------------------------------- 1 | From jamis_buck@byu.edu Mon May 2 16:07:05 2005 2 | MIME-Version: 1.0 (Apple Message framework v622) 3 | Content-Transfer-Encoding: base64 4 | Message-Id: 5 | Content-Type: text/plain; 6 | charset=EUC-KR; 7 | format=flowed 8 | To: willard15georgina@jamis.backpackit.com 9 | From: Jamis Buck 10 | Subject: =?EUC-KR?Q?NOTE:_=C7=D1=B1=B9=B8=BB=B7=CE_=C7=CF=B4=C2_=B0=CD?= 11 | Date: Mon, 2 May 2005 16:07:05 -0600 12 | 13 | tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin 14 | wLogSmFtaXPA1LTPtNku 15 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email10.eml: -------------------------------------------------------------------------------- 1 | Return-Path: 2 | Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for ; Tue, 10 May 2005 15:27:05 -0500 3 | Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for ; Tue, 10 May 2005 15:27:04 -0500 4 | Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for ; Tue, 10 May 2005 15:27:03 -0500 5 | Date: Tue, 10 May 2005 15:27:03 -0500 6 | From: xxx@xxxx.xxx 7 | Sender: xxx@xxxx.xxx 8 | To: xxxxxxxxxxx@xxxx.xxxx.xxx 9 | Message-Id: 10 | X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx 11 | Delivered-To: xxx@xxxx.xxx 12 | Importance: normal 13 | Content-Type: text/plain; charset=X-UNKNOWN 14 | 15 | Test test. Hi. Waving. m 16 | 17 | ---------------------------------------------------------------- 18 | Sent via Bell Mobility's Text Messaging service. 19 | Envoyé par le service de messagerie texte de Bell Mobilité. 20 | ---------------------------------------------------------------- 21 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email5.eml: -------------------------------------------------------------------------------- 1 | Return-Path: 2 | Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for ; Tue, 10 May 2005 15:27:05 -0500 3 | Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for ; Tue, 10 May 2005 15:27:04 -0500 4 | Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for ; Tue, 10 May 2005 15:27:03 -0500 5 | Date: Tue, 10 May 2005 15:27:03 -0500 6 | From: xxx@xxxx.xxx 7 | Sender: xxx@xxxx.xxx 8 | To: xxxxxxxxxxx@xxxx.xxxx.xxx 9 | Message-Id: 10 | X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx 11 | Delivered-To: xxx@xxxx.xxx 12 | Importance: normal 13 | 14 | Test test. Hi. Waving. m 15 | 16 | ---------------------------------------------------------------- 17 | Sent via Bell Mobility's Text Messaging service. 18 | Envoyé par le service de messagerie texte de Bell Mobilité. 19 | ---------------------------------------------------------------- 20 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email6.eml: -------------------------------------------------------------------------------- 1 | Return-Path: 2 | Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id C1B953B4CB6 for ; Tue, 10 May 2005 15:27:05 -0500 3 | Received: from SMS-GTYxxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id ca for ; Tue, 10 May 2005 15:27:04 -0500 4 | Received: from xxx.xxxx.xxx by SMS-GTYxxx.xxxx.xxx with ESMTP id j4AKR3r23323 for ; Tue, 10 May 2005 15:27:03 -0500 5 | Date: Tue, 10 May 2005 15:27:03 -0500 6 | From: xxx@xxxx.xxx 7 | Sender: xxx@xxxx.xxx 8 | To: xxxxxxxxxxx@xxxx.xxxx.xxx 9 | Message-Id: 10 | X-Original-To: xxxxxxxxxxx@xxxx.xxxx.xxx 11 | Delivered-To: xxx@xxxx.xxx 12 | Importance: normal 13 | Content-Type: text/plain; charset=us-ascii 14 | 15 | Test test. Hi. Waving. m 16 | 17 | ---------------------------------------------------------------- 18 | Sent via Bell Mobility's Text Messaging service. 19 | Envoyé par le service de messagerie texte de Bell Mobilité. 20 | ---------------------------------------------------------------- 21 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email8.eml: -------------------------------------------------------------------------------- 1 | From xxxxxxxxx.xxxxxxx@gmail.com Sun May 8 19:07:09 2005 2 | Return-Path: 3 | Message-ID: 4 | Date: Sun, 8 May 2005 14:09:11 -0500 5 | From: xxxxxxxxx xxxxxxx 6 | Reply-To: xxxxxxxxx xxxxxxx 7 | To: xxxxx xxxx 8 | Subject: Fwd: Signed email causes file attachments 9 | In-Reply-To: 10 | MIME-Version: 1.0 11 | Content-Type: multipart/mixed; 12 | boundary="----=_Part_5028_7368284.1115579351471" 13 | References: 14 | 15 | ------=_Part_5028_7368284.1115579351471 16 | Content-Type: text/plain; charset=ISO-8859-1 17 | Content-Transfer-Encoding: quoted-printable 18 | Content-Disposition: inline 19 | 20 | We should not include these files or vcards as attachments. 21 | 22 | ---------- Forwarded message ---------- 23 | From: xxxxx xxxxxx 24 | Date: May 8, 2005 1:17 PM 25 | Subject: Signed email causes file attachments 26 | To: xxxxxxx@xxxxxxxxxx.com 27 | 28 | 29 | Hi, 30 | 31 | Test attachments oddly encoded with japanese charset. 32 | 33 | 34 | ------=_Part_5028_7368284.1115579351471 35 | Content-Type: application/octet-stream; name*=iso-2022-jp'ja'01%20Quien%20Te%20Dij%8aat.%20Pitbull.mp3 36 | Content-Transfer-Encoding: base64 37 | Content-Disposition: attachment 38 | 39 | MIAGCSqGSIb3DQEHAqCAMIACAQExCzAJBgUrDgMCGgUAMIAGCSqGSIb3DQEHAQAAoIIGFDCCAs0w 40 | ggI2oAMCAQICAw5c+TANBgkqhkiG9w0BAQQFADBiMQswCQYDVQQGEwJaQTElMCMGA1UEChMcVGhh 41 | d3RlIENvbnN1bHRpbmcgKFB0eSkgTHRkLjEsMCoGA1UEAxMjVGhhd3RlIFBlcnNvbmFsIEZyZWVt 42 | YWlsIElzc3VpbmcgQ0EwHhcNMDUwMzI5MDkzOTEwWhcNMDYwMzI5MDkzOTEwWjBCMR8wHQYDVQQD 43 | ExZUaGF3dGUgRnJlZW1haWwgTWVtYmVyMR8wHQYJKoZIhvcNAQkBFhBzbWhhdW5jaEBtYWMuY29t 44 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAn90dPsYS3LjfMY211OSYrDQLzwNYPlAL 45 | 7+/0XA+kdy8/rRnyEHFGwhNCDmg0B6pxC7z3xxJD/8GfCd+IYUUNUQV5m9MkxfP9pTVXZVIYLaBw 46 | ------=_Part_5028_7368284.1115579351471-- 47 | 48 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_double_at_in_header.eml: -------------------------------------------------------------------------------- 1 | From jamis_buck@byu.edu Mon May 2 16:07:05 2005 2 | MIME-Version: 1.0 (Apple Message framework v622) 3 | Content-Transfer-Encoding: base64 4 | Message-Id: 5 | Content-Type: text/plain; 6 | charset=EUC-KR; 7 | format=flowed 8 | To: willard15georgina@jamis.backpackit.com 9 | From: Jamis Buck 10 | Subject: =?EUC-KR?Q?NOTE:_=C7=D1=B1=B9=B8=BB=B7=CE_=C7=CF=B4=C2_=B0=CD?= 11 | Date: Mon, 2 May 2005 16:07:05 -0600 12 | 13 | tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin 14 | wLogSmFtaXPA1LTPtNku 15 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_incorrect_header.eml: -------------------------------------------------------------------------------- 1 | Received: from xxx.xxx.xxx ([xxx.xxx.xxx.xxx] verified) 2 | by xxx.com (CommuniGate Pro SMTP 4.2.8) 3 | with SMTP id 2532598 for xxx@xxx.com; Wed, 23 Feb 2005 17:51:49 -0500 4 | Received-SPF: softfail 5 | receiver=xxx.com; client-ip=xxx.xxx.xxx.xxx; envelope-from=xxx@xxx.xxx 6 | quite Delivered-To: xxx@xxx.xxx 7 | Received: by xxx.xxx.xxx (Wostfix, from userid xxx) 8 | id 0F87F333; Wed, 23 Feb 2005 16:16:17 -0600 9 | Date: Wed, 23 Feb 2005 18:20:17 -0400 10 | From: "xxx xxx" 11 | Message-ID: <4D6AA7EB.6490534@xxx.xxx> 12 | To: xxx@xxx.com 13 | Subject: Stop adware/spyware once and for all. 14 | X-Scanned-By: MIMEDefang 2.11 (www dot roaringpenguin dot com slash mimedefang) 15 | 16 | You are infected with: 17 | Ad Ware and Spy Ware 18 | 19 | Get your free scan and removal download now, 20 | before it gets any worse. 21 | 22 | http://xxx.xxx.info?aid=3D13&?stat=3D4327kdzt 23 | 24 | 25 | 26 | 27 | no more? (you will still be infected) 28 | http://xxx.xxx.info/discon/?xxx@xxx.com 29 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_multiple_from.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: tim@powerupdev.com 2 | Return-Path: 3 | To: tim@powerupdev.com concierge@powerupdev.com 4 | From: tim@powerupdev.com concierge@powerupdev.com 5 | Subject: /home/svn/public/minebox revision 214 6 | Reply-to: tim@powerupdev.com concierge@powerupdev.com 7 | Message-Id: <20071022234523.5BD8E86D2@mangaverde.net> 8 | Date: Mon, 22 Oct 2007 23:45:23 +0000 (UTC) 9 | 10 |

recordkick 2007-10-22 23:45:23 +0000 (Mon, 22 Oct 2007)

test 11 | subversion
12 |


Modified:
13 | trunk/README
14 | ===================================================================
15 | --- trunk/README\t2007-10-22
16 | 23:41:34 UTC (rev 213)
17 | +++ trunk/README\t2007-10-22 23:45:23 UTC (rev 214)
18 | @@ -1,5 +1,5 @@
19 |  == Welcome
20 | to Rails
21 | -Test
22 | +Tedst
23 |  Rails is a web-application and persistence framework that includes everything
24 |  needed
25 | to create database-backed web-applications according to the
26 |  Model-View-Control pattern of separation. This pattern
27 | splits the view (also
28 | 
29 | 
30 | 
31 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_quoted_with_0d0a.eml: -------------------------------------------------------------------------------- 1 | MIME-Version: 1.0 (Apple Message framework v730) 2 | Message-Id: <9169D984-4E0B-45EF-82D4-8F5E53AD7012@example.com> 3 | From: foo@example.com 4 | Subject: testing 5 | Date: Mon, 6 Jun 2005 22:21:22 +0200 6 | To: blah@example.com 7 | Content-Transfer-Encoding: quoted-printable 8 | Content-Type: text/plain 9 | 10 | A fax has arrived from remote ID ''.=0D=0A-----------------------= 11 | -------------------------------------=0D=0ATime: 3/9/2006 3:50:52= 12 | PM=0D=0AReceived from remote ID: =0D=0AInbound user ID XXXXXXXXXX, r= 13 | outing code XXXXXXXXX=0D=0AResult: (0/352;0/0) Successful Send=0D=0AP= 14 | age record: 1 - 1=0D=0AElapsed time: 00:58 on channel 11=0D=0A 15 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_reply.eml: -------------------------------------------------------------------------------- 1 | Return-Path: 2 | Received: from me ([unix socket]) 3 | by xxxxx1.xxxx.net (Cyrus v2.2.12) with LMTPA; 4 | Sun, 18 Nov 2007 00:56:33 -0800 5 | Received: from smtp.xxxx.org (unknown [127.0.0.1]) 6 | by xxxxx1.xxxx.net (Postfix) with ESMTP id F128477EB5; 7 | Sun, 18 Nov 2007 00:56:32 -0800 (PST) 8 | Received: from omta02sl.mx.bigpond.com (omta02sl.mx.bigpond.com [144.140.93.154]) 9 | by smtp.xxxx.org (Postfix) with ESMTP id 2D567ACC08; 10 | Sun, 18 Nov 2007 00:56:28 -0800 (PST) 11 | Received: from oaamta05sl.mx.bigpond.com ([124.183.219.10]) 12 | by omta02sl.mx.bigpond.com with ESMTP 13 | id <20071118085627.YVPI22254.omta02sl.mx.bigpond.com@oaamta05sl.mx.bigpond.com>; 14 | Sun, 18 Nov 2007 08:56:27 +0000 15 | Received: from [10.0.0.1] (really [124.183.219.10]) 16 | by oaamta05sl.mx.bigpond.com with ESMTP 17 | id <20071118085627.TQWF6995.oaamta05sl.mx.bigpond.com@[10.0.0.1]>; 18 | Sun, 18 Nov 2007 08:56:27 +0000 19 | Message-ID: <473FFE27.20003@xxx.org> 20 | Date: Sun, 18 Nov 2007 19:56:07 +1100 21 | From: Testing 22 | User-Agent: Mozilla Thunderbird 1.0.6 (Windows/20050716) 23 | X-Accept-Language: en-us, en 24 | MIME-Version: 1.0 25 | To: Mikel Lindsaar 26 | Subject: Re: Test reply email 27 | References: <473FF3B8.9020707@xxx.org> <348F04F142D69C21-291E56D292BC@xxxx.net> 28 | In-Reply-To: <348F04F142D69C21-291E56D292BC@xxxx.net> 29 | Content-Type: text/plain; charset=US-ASCII; format=flowed 30 | Content-Transfer-Encoding: 7bit 31 | 32 | Message body 33 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_simple.eml: -------------------------------------------------------------------------------- 1 | From mike@nowhere.com 2 | Return-Path: 3 | Received: from mikel091a by oaamta05sl.mx.bigpond.com with SMTP id <20071021093820.JFMT24025.oaamta05sl.mx.bigpond.com@mikel091a> for ; Sun, 21 Oct 2007 19:38:20 +1000 4 | Date: Sun, 21 Oct 2007 19:38:13 +1000 5 | From: Mikel Lindsaar 6 | To: Mikel 7 | Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a> 8 | Subject: Testing outlook 9 | 10 | Hello Mikel 11 | 12 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_string_in_date_field.eml: -------------------------------------------------------------------------------- 1 | From mikel@me.com Mon May 2 16:07:05 2005 2 | MIME-Version: 1.0 (Apple Message framework v622) 3 | Received: from jsj1wlrmd001.webex.com (by jsj1wlrmd001.webex.com 4 | (8.12.10/8.12.11) with ESMTP id m8MKKPTs022429 5 | for ; Mon, 22 Sep 2008 20:20:25 GMT 6 | Content-Transfer-Encoding: base64 7 | Message-Id: 8 | Content-Type: text/plain; 9 | charset=EUC-KR; 10 | format=flowed 11 | To: bob@bob.com 12 | From: mikel@me.com 13 | Subject: =?EUC-KR?Q?NOTE:_=C7=D1=B1=B9=B8=BB=B7=CE_=C7=CF=B4=C2_=B0=CD?= 14 | Date: Sat, 20 Sep 2008 20:04:30 +0300 (ùòåï ÷éõ éøåùìéí) 15 | 16 | tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin 17 | wLogSmFtaXPA1LTPtNku 18 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_trailing_dot.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: xxx@xxx.com 2 | Received: by 10.67.31.8 with SMTP id i8cs1195ugj; 3 | Mon, 22 Sep 2008 13:45:18 -0700 (PDT) 4 | Received: by 10.100.207.5 with SMTP id e5mr3483815ang.104.1222110393505; 5 | Mon, 22 Sep 2008 12:06:33 -0700 (PDT) 6 | Return-Path: 7 | Received: from rubyforge.org (rubyforge.org [205.234.109.19]) 8 | by mx.google.com with ESMTP id c2si899474ana.10.2008.09.22.12.06.28; 9 | Mon, 22 Sep 2008 12:06:33 -0700 (PDT) 10 | Received-SPF: pass (google.com: best guess record for domain of noreply@rubyforge.org designates 205.234.109.19 as permitted sender) client-ip=205.234.109.19; 11 | Authentication-Results: mx.google.com; spf=pass (google.com: best guess record for domain of noreply@rubyforge.org designates 205.234.109.19 as permitted sender) smtp.mail=noreply@rubyforge.org 12 | Received: by rubyforge.org (Postfix, from userid 502) 13 | id 8FB1518581AC; Mon, 22 Sep 2008 15:06:28 -0400 (EDT) 14 | To: noreply@rubyforge.org 15 | From: Sandy M. 16 | Subject: [skynet-help][60666] How are intermediate files handled in SkyNet? 17 | Content-type: text/plain; charset=UTF-8 18 | Message-Id: <20080922190628.8FB1518581AC@rubyforge.org> 19 | Date: Mon, 22 Sep 2008 15:06:28 -0400 (EDT) 20 | 21 | Testing, testing, 123. -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_with_at_display_name.eml: -------------------------------------------------------------------------------- 1 | Delivered-To: raasdnil@gmail.com 2 | Received: by 10.140.178.13 with SMTP id a13cs354079rvf; 3 | Fri, 21 Nov 2008 20:05:05 -0800 (PST) 4 | Received: by 10.151.44.15 with SMTP id w15mr2254748ybj.98.1227326704711; 5 | Fri, 21 Nov 2008 20:05:04 -0800 (PST) 6 | Return-Path: 7 | Received: from mail11.tpgi.com.au (mail11.tpgi.com.au [203.12.160.161]) 8 | by mx.google.com with ESMTP id 10si5117885gxk.81.2008.11.21.20.05.03; 9 | Fri, 21 Nov 2008 20:05:04 -0800 (PST) 10 | Received-SPF: neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) client-ip=203.12.160.161; 11 | Authentication-Results: mx.google.com; spf=neutral (google.com: 203.12.160.161 is neither permitted nor denied by domain of test@lindsaar.net) smtp.mail=test@lindsaar.net 12 | X-TPG-Junk-Status: Message not scanned 13 | X-TPG-Antivirus: Passed 14 | Received: from [192.0.0.253] (60-241-138-146.static.tpgi.com.au [60.0.0.146]) 15 | by mail11.tpgi.com.au (envelope-from test@lindsaar.net) (8.14.3/8.14.3) with ESMTP id mAM44xew022221 16 | for ; Sat, 22 Nov 2008 15:05:01 +1100 17 | Message-Id: <6B7EC235-5B17-4CA8-B2B8-39290DEB43A3@test.lindsaar.net> 18 | From: Mikel Lindsaar , jack@lindsar.com 19 | To: smith@gmail.com, Mikel@Lindsaar , tom@gmail.com 20 | Content-Type: text/plain; charset=US-ASCII; format=flowed 21 | Content-Transfer-Encoding: 7bit 22 | MIME-Version: 1.0 (Apple Message framework v929.2) 23 | Subject: Testing 123 24 | Date: Sat, 22 Nov 2008 15:04:59 +1100 25 | X-Mailer: Apple Mail (2.929.2) 26 | 27 | Plain email. 28 | 29 | Hope it works well! 30 | 31 | Mikel 32 | -------------------------------------------------------------------------------- /spec/fixtures/emails/plain_emails/raw_email_with_partially_quoted_subject.eml: -------------------------------------------------------------------------------- 1 | From jamis@37signals.com Mon May 2 16:07:05 2005 2 | MIME-Version: 1.0 (Apple Message framework v622) 3 | Content-Transfer-Encoding: base64 4 | Message-Id: 5 | Content-Type: text/plain; 6 | charset=EUC-KR; 7 | format=flowed 8 | To: jamis@37signals.com 9 | From: Jamis Buck 10 | Subject: Re: Test: =?UTF-8?B?Iua8ouWtlyI=?= mid =?UTF-8?B?Iua8ouWtlyI=?= tail 11 | Date: Mon, 2 May 2005 16:07:05 -0600 12 | 13 | tOu6zrrQwMcguLbC+bChwfa3ziwgv+y4rrTCIMfPs6q01MC7ILnPvcC0z7TZLg0KDQrBpiDAzLin 14 | wLogSmFtaXPA1LTPtNku 15 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example01.eml: -------------------------------------------------------------------------------- 1 | From: John Doe 2 | To: Mary Smith 3 | Subject: Saying Hello 4 | Date: Fri, 21 Nov 1997 09:55:06 -0600 5 | Message-ID: <1234@local.machine.example> 6 | 7 | This is a message just to say hello. 8 | So, "Hello". 9 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example02.eml: -------------------------------------------------------------------------------- 1 | From: John Doe 2 | Sender: Michael Jones 3 | To: Mary Smith 4 | Subject: Saying Hello 5 | Date: Fri, 21 Nov 1997 09:55:06 -0600 6 | Message-ID: <1234@local.machine.example> 7 | 8 | This is a message just to say hello. 9 | So, "Hello". 10 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example03.eml: -------------------------------------------------------------------------------- 1 | From: "Joe Q. Public" 2 | To: Mary Smith , jdoe@example.org, Who? 3 | Cc: , "Giant; \"Big\" Box" 4 | Date: Tue, 1 Jul 2003 10:52:37 +0200 5 | Message-ID: <5678.21-Nov-1997@example.com> 6 | 7 | Hi everyone. 8 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example04.eml: -------------------------------------------------------------------------------- 1 | From: Pete 2 | To: A Group:Chris Jones ,joe@where.test,John ; 3 | Cc: Undisclosed recipients:; 4 | Date: Thu, 13 Feb 1969 23:32:54 -0330 5 | Message-ID: 6 | 7 | Testing. 8 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example05.eml: -------------------------------------------------------------------------------- 1 | From: John Doe 2 | To: Mary Smith 3 | Subject: Saying Hello 4 | Date: Fri, 21 Nov 1997 09:55:06 -0600 5 | Message-ID: <1234@local.machine.example> 6 | 7 | This is a message just to say hello. 8 | So, "Hello". 9 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example06.eml: -------------------------------------------------------------------------------- 1 | From: Mary Smith 2 | To: John Doe 3 | Reply-To: "Mary Smith: Personal Account" 4 | Subject: Re: Saying Hello 5 | Date: Fri, 21 Nov 1997 10:01:10 -0600 6 | Message-ID: <3456@example.net> 7 | In-Reply-To: <1234@local.machine.example> 8 | References: <1234@local.machine.example> 9 | 10 | This is a reply to your hello. 11 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example07.eml: -------------------------------------------------------------------------------- 1 | To: "Mary Smith: Personal Account" 2 | From: John Doe 3 | Subject: Re: Saying Hello 4 | Date: Fri, 21 Nov 1997 11:00:00 -0600 5 | Message-ID: 6 | In-Reply-To: <3456@example.net> 7 | References: <1234@local.machine.example> <3456@example.net> 8 | 9 | This is a reply to your reply. 10 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example08.eml: -------------------------------------------------------------------------------- 1 | Resent-From: Mary Smith 2 | Resent-To: Jane Brown 3 | Resent-Date: Mon, 24 Nov 1997 14:22:01 -0800 4 | Resent-Message-ID: <78910@example.net> 5 | From: John Doe 6 | To: Mary Smith 7 | Subject: Saying Hello 8 | Date: Fri, 21 Nov 1997 09:55:06 -0600 9 | Message-ID: <1234@local.machine.example> 10 | 11 | This is a message just to say hello. 12 | So, "Hello". 13 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example09.eml: -------------------------------------------------------------------------------- 1 | Received: from x.y.test 2 | by example.net 3 | via TCP 4 | with ESMTP 5 | id ABC12345 6 | for ; 21 Nov 1997 10:05:43 -0600 7 | Received: from machine.example by x.y.test; 21 Nov 1997 10:01:22 -0600 8 | From: John Doe 9 | To: Mary Smith 10 | Subject: Saying Hello 11 | Date: Fri, 21 Nov 1997 09:55:06 -0600 12 | Message-ID: <1234@local.machine.example> 13 | 14 | This is a message just to say hello. 15 | So, "Hello". 16 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example10.eml: -------------------------------------------------------------------------------- 1 | From: Pete(A wonderful \) chap) 2 | To:A Group(Some people) 3 | :Chris Jones , 4 | joe@example.org, 5 | John (my dear friend); (the end of the group) 6 | Cc:(Empty list)(start)Undisclosed recipients :(nobody(that I know)) ; 7 | Date: Thu, 8 | 13 9 | Feb 10 | 1969 11 | 23:32 12 | -0330 (Newfoundland Time) 13 | Message-ID: 14 | 15 | Testing. 16 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example11.eml: -------------------------------------------------------------------------------- 1 | From: Joe Q. Public 2 | To: Mary Smith <@machine.tld:mary@example.net>, , jdoe@test . example 3 | Date: Tue, 1 Jul 2003 10:52:37 +0200 4 | Message-ID: <5678.21-Nov-1997@example.com> 5 | 6 | Hi everyone. 7 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example12.eml: -------------------------------------------------------------------------------- 1 | From: John Doe 2 | To: Mary Smith 3 | Subject: Saying Hello 4 | Date: 21 Nov 97 09:55:06 GMT 5 | Message-ID: <1234@local.machine.example> 6 | 7 | This is a message just to say hello. 8 | So, "Hello". 9 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example13.eml: -------------------------------------------------------------------------------- 1 | From : John Doe 2 | To : Mary Smith 3 | __ 4 | 5 | Subject : Saying Hello 6 | Date : Fri, 21 Nov 1997 09(comment): 55 : 06 -0600 7 | Message-ID : <1234 @ local(blah) .machine .example> 8 | 9 | This is a message just to say hello. 10 | So, "Hello". 11 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc2822/example14.eml: -------------------------------------------------------------------------------- 1 | From test@example.com Mon Aug 22 09:45:15 2011 2 | Date: Fri, 19 Aug 2011 10:47:17 +0900 3 | From: Atsushi Yoshida 4 | Reply-To: rudeboyjet@gmail.com 5 | Subject: Re: TEST 6 | 7 | =?ISO-2022-JP?B?GyRCJUYlOSVIGyhC?= 8 | =?ISO-2022-JP?B?GyRCJUYlOSVIGyhC?= 9 | To: rudeboyjet@gmail.com 10 | Message-Id: <0CC5E11ED2C1D@example.com> 11 | In-Reply-To: 12 | MIME-Version: 1.0 13 | Content-Type: text/plain; charset=iso-2022-jp 14 | Content-Transfer-Encoding: 7bit 15 | 16 | Hello 17 | -------------------------------------------------------------------------------- /spec/fixtures/emails/rfc6532/utf8_headers.eml: -------------------------------------------------------------------------------- 1 | From: "Jöhn Doe" 2 | To: "Märy Smith" 3 | Subject: Säying Hello 4 | 5 | body 6 | -------------------------------------------------------------------------------- /spec/fixtures/emails/sample_output_multipart: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mikel/mail/d1d65b370b109b98e673a934e8b70a0c1f58cc59/spec/fixtures/emails/sample_output_multipart -------------------------------------------------------------------------------- /spec/mail/core_extensions_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe Object do 6 | 7 | end 8 | -------------------------------------------------------------------------------- /spec/mail/elements/date_time_element_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::DateTimeElement do 5 | 6 | it "should parse a date" do 7 | date_text = 'Wed, 27 Apr 2005 14:15:31 -0700' 8 | expect { Mail::DateTimeElement.new(date_text) }.not_to raise_error 9 | end 10 | 11 | it "should raise an error if the input is nil" do 12 | date_text = nil 13 | expect { Mail::DateTimeElement.new(date_text) }.to raise_error(Mail::Field::ParseError) 14 | end 15 | 16 | it "should raise an error if the input is useless" do 17 | date_text = '""""""""""""""""' 18 | expect { Mail::DateTimeElement.new(date_text) }.to raise_error(Mail::Field::ParseError) 19 | end 20 | 21 | end 22 | -------------------------------------------------------------------------------- /spec/mail/elements/envelope_from_element_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::EnvelopeFromElement do 5 | 6 | describe "parsing a from envelope string" do 7 | it "should parse a full field" do 8 | expect { Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 7 00:39:21 2009") }.not_to raise_error 9 | end 10 | 11 | it "should parse a full field with a double digit day" do 12 | expect { Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") }.not_to raise_error 13 | end 14 | 15 | it "should parse a full field with a single space day" do 16 | expect { Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") }.not_to raise_error 17 | end 18 | 19 | it "should parse a null sender, when specified as <>" do 20 | expect { Mail::EnvelopeFromElement.new("<> Mon Aug 17 00:39:21 2009") }.not_to raise_error 21 | end 22 | 23 | it "should parse a null sender, with a single space day" do 24 | expect { Mail::EnvelopeFromElement.new("<> Mon Aug 17 00:39:21 2009") }.not_to raise_error 25 | end 26 | end 27 | 28 | describe "accessor methods" do 29 | it "should return the address" do 30 | envelope = Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") 31 | expect(envelope.address).to eq "mikel@test.lindsaar.net" 32 | end 33 | 34 | it "should return the date_time" do 35 | envelope = Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") 36 | expect(envelope.date_time).to eq ::DateTime.parse("Mon Aug 17 00:39:21 2009") 37 | end 38 | end 39 | 40 | describe 'formatting' do 41 | it 'should format delivery date using UNIX ctime style' do 42 | time = Time.now 43 | envelope = Mail::EnvelopeFromElement.new("mikel@test.lindsaar.net #{time.ctime}") 44 | expect(envelope.to_s).to eq "mikel@test.lindsaar.net #{time.ctime}" 45 | end 46 | end 47 | 48 | end 49 | -------------------------------------------------------------------------------- /spec/mail/elements/message_ids_element_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::MessageIdsElement do 5 | 6 | it "should parse a message_id" do 7 | msg_id_text = '<1234@test.lindsaar.net>' 8 | expect { Mail::MessageIdsElement.new(msg_id_text) }.not_to raise_error 9 | end 10 | 11 | it "should parse multiple message_ids" do 12 | msg_id_text = '<1234@test.lindsaar.net> <1234@test.lindsaar.net>' 13 | expect { Mail::MessageIdsElement.new(msg_id_text) }.not_to raise_error 14 | end 15 | 16 | it "treats nil as an empty list" do 17 | element = Mail::MessageIdsElement.new(nil) 18 | expect(element.message_ids).to eq [] 19 | expect(element.message_id).to be_nil 20 | end 21 | 22 | it "should raise an error if the input is useless" do 23 | msg_id_text = '""""""""""""""""' 24 | expect { Mail::MessageIdsElement.new(msg_id_text) }.to raise_error(Mail::Field::ParseError) 25 | end 26 | 27 | it "should respond to message_ids" do 28 | msg_id_text = '<1234@test.lindsaar.net> <1234@test.lindsaar.net>' 29 | msg_ids = Mail::MessageIdsElement.new(msg_id_text) 30 | expect(msg_ids.message_ids).to eq ['1234@test.lindsaar.net', '1234@test.lindsaar.net'] 31 | end 32 | 33 | it "should respond to message_id" do 34 | msg_id_text = '<1234@test.lindsaar.net>' 35 | msg_ids = Mail::MessageIdsElement.new(msg_id_text) 36 | expect(msg_ids.message_id).to eq '1234@test.lindsaar.net' 37 | end 38 | 39 | it "should not fail to parse a message id with dots in it" do 40 | text = "<4afb664ca3078_48dc..fdbe32b865532b@ax-desktop.mail>" 41 | m = Mail::MessageIdsElement.new(text) 42 | expect(m.message_id).to eq "4afb664ca3078_48dc..fdbe32b865532b@ax-desktop.mail" 43 | end 44 | 45 | end 46 | -------------------------------------------------------------------------------- /spec/mail/elements/phrase_list_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe Mail::PhraseList do 6 | 7 | describe "parsing" do 8 | it "should parse a phrase list" do 9 | parse_text = '"Mikel Lindsaar", "Mikel", you, somewhere' 10 | expect { Mail::PhraseList.new(parse_text) }.not_to raise_error 11 | end 12 | 13 | it "treats nil as an empty list" do 14 | list = Mail::PhraseList.new(nil) 15 | expect(list.phrases).to eq [] 16 | end 17 | 18 | it "should not raise an error if the input is useless" do 19 | parse_text = '""""""""""""""""' 20 | expect(Mail::PhraseList.new(parse_text).phrases).to eq [parse_text[1...-1]] 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/mail/elements/received_element_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::ReceivedElement do 5 | 6 | it "should raise an error if the input is nil" do 7 | received = Mail::ReceivedElement.new(nil) 8 | expect(received.info).to be_nil 9 | expect(received.date_time).to be_nil 10 | end 11 | 12 | it "should raise an error if the input is useless" do 13 | received_text = '""""""""""""""""' 14 | expect { Mail::ReceivedElement.new(received_text) }.to raise_error(Mail::Field::ParseError) 15 | end 16 | 17 | it "should give back the date time" do 18 | received_text = 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)' 19 | date_text = '10 May 2005 17:26:50 +0000 (GMT)' 20 | rec = Mail::ReceivedElement.new(received_text) 21 | expect(rec.date_time).to eq ::DateTime.parse(date_text) 22 | end 23 | 24 | it "should give back the info" do 25 | received_text = 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ; Tue, 10 May 2005 17:26:50 +0000 (GMT)' 26 | info_text = 'from localhost (localhost [127.0.0.1]) by xxx.xxxxx.com (Postfix) with ESMTP id 50FD3A96F for ' 27 | rec = Mail::ReceivedElement.new(received_text) 28 | expect(rec.info).to eq info_text 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/mail/encodings/base64_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::Encodings::Base64 do 5 | 6 | it "should encode base 64 from text" do 7 | result = "VGhpcyBpcyBhIHRlc3Q=\r\n" 8 | expect(Mail::Encodings::Base64.encode('This is a test')).to eq result 9 | end 10 | 11 | it "should decode base 64 text" do 12 | result = 'This is a test' 13 | expect(Mail::Encodings::Base64.decode("VGhpcyBpcyBhIHRlc3Q=\n")).to eq result 14 | end 15 | 16 | it "should encode base 64 from binary" do 17 | result = "AAAAAA==\r\n" 18 | expect(Mail::Encodings::Base64.encode("\000\000\000\000")).to eq result 19 | end 20 | 21 | it "should decode base 64 text" do 22 | result = "\000\000\000\000" 23 | expect(Mail::Encodings::Base64.decode("AAAAAA==\n")).to eq result 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /spec/mail/encodings/transfer_encoding_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::Encodings::TransferEncoding do 5 | it "accepts blank message_encoding" do 6 | expect(described_class.negotiate('', '7bit', '')).to eq Mail::Encodings::SevenBit 7 | expect(described_class.negotiate('', '8bit', '')).to eq Mail::Encodings::EightBit 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /spec/mail/encodings/unix_to_unix_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe Mail::Encodings::UnixToUnix do 6 | def decode(str) 7 | Mail::Encodings::UnixToUnix.decode(str) 8 | end 9 | 10 | def encode(str) 11 | Mail::Encodings::UnixToUnix.encode(str) 12 | end 13 | 14 | it "is registered as uuencode" do 15 | expect(Mail::Encodings.get_encoding('uuencode')).to eq(Mail::Encodings::UnixToUnix) 16 | end 17 | 18 | it "is registered as x-uuencode" do 19 | expect(Mail::Encodings.get_encoding('x-uuencode')).to eq(Mail::Encodings::UnixToUnix) 20 | end 21 | 22 | it "is registered as x-uue" do 23 | expect(Mail::Encodings.get_encoding('x-uue')).to eq(Mail::Encodings::UnixToUnix) 24 | end 25 | 26 | it "can transport itself" do 27 | expect(Mail::Encodings::UnixToUnix.can_transport?(Mail::Encodings::UnixToUnix)).to be_truthy 28 | end 29 | 30 | it "decodes" do 31 | text = strip_heredoc(<<-TEXT) 32 | begin 644 Happy.txt 33 | M2&%P<'D@=&]D87D@9F]R('1O(&)E(&]N92!O9B!P96%C92!A;F0@; Sun, 8 May 2005 12:30:23 -0500") 17 | fl << Mail::Field.parse("Return-Path: mikel@me.com") 18 | expect(fl.map(&:name)).to eq %w[ Return-Path Received From To ] 19 | end 20 | 21 | it "should add new Received items after the existing ones" do 22 | fl = Mail::FieldList.new 23 | fl << Mail::Field.parse("To: mikel@me.com") 24 | fl << Mail::Field.parse("From: mikel@me.com") 25 | fl << Mail::Field.parse("Received: from xxx.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ; Sun, 8 May 2005 12:30:23 -0500") 26 | fl << Mail::Field.parse("Return-Path: mikel@me.com") 27 | fl << Mail::Field.parse("Received: from 123.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ; Sun, 8 May 2005 12:30:23 -0500") 28 | expect(fl[2].field.value).to eq 'from 123.xxxx.xxx by xxx.xxxx.xxx with ESMTP id 6AAEE3B4D23 for ; Sun, 8 May 2005 12:30:23 -0500' 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /spec/mail/fields/address_container_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe 'AddressContainer' do 6 | it "should allow you to append an address to an address field result" do 7 | m = Mail.new("To: mikel@test.lindsaar.net") 8 | expect(m.to).to eq ['mikel@test.lindsaar.net'] 9 | m.to << 'bob@test.lindsaar.net' 10 | expect(m.to).to eq ['mikel@test.lindsaar.net', 'bob@test.lindsaar.net'] 11 | end 12 | 13 | it "should handle complex addresses correctly" do 14 | m = Mail.new("From: mikel@test.lindsaar.net") 15 | expect(m.from).to eq ['mikel@test.lindsaar.net'] 16 | m.from << '"Ada Lindsaar" , bob@test.lindsaar.net' 17 | expect(m.from).to eq ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net', 'bob@test.lindsaar.net'] 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /spec/mail/fields/comments_field_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe Mail::CommentsField do 6 | # 7 | # comments = "Comments:" unstructured CRLF 8 | 9 | it "should initialize" do 10 | expect { Mail::CommentsField.new("this is a comment") }.not_to raise_error 11 | end 12 | 13 | it "should accept a string with the field name" do 14 | t = Mail::CommentsField.new('this is a comment') 15 | expect(t.name).to eq 'Comments' 16 | expect(t.value).to eq 'this is a comment' 17 | end 18 | 19 | 20 | end 21 | -------------------------------------------------------------------------------- /spec/mail/fields/common_date_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::CommonDateField do 5 | describe "encoding and decoding fields" do 6 | it "should allow us to encode an date field" do 7 | field = Mail::DateField.new('12 Aug 2009 00:00:02 GMT') 8 | expect(field.encoded).to eq "Date: Wed, 12 Aug 2009 00:00:02 +0000\r\n" 9 | end 10 | 11 | it "should allow us to encode an resent date field" do 12 | field = Mail::ResentDateField.new('12 Aug 2009 00:00:02 GMT') 13 | expect(field.encoded).to eq "Resent-Date: Wed, 12 Aug 2009 00:00:02 +0000\r\n" 14 | end 15 | 16 | it "should allow us to decode an address field" do 17 | field = Mail::DateField.new('12 Aug 2009 00:00:02 GMT') 18 | expect(field.decoded).to eq "Wed, 12 Aug 2009 00:00:02 +0000" 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /spec/mail/fields/common_message_id_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::CommonMessageIdField do 5 | 6 | describe "encoding and decoding fields" do 7 | 8 | it "should allow us to encode a message id field" do 9 | field = Mail::MessageIdField.new('') 10 | expect(field.encoded).to eq "Message-ID: \r\n" 11 | end 12 | 13 | it "should allow us to encode a message id field" do 14 | field = Mail::MessageIdField.new('<1234@test.lindsaar.net>') 15 | expect(field.encoded).to eq "Message-ID: <1234@test.lindsaar.net>\r\n" 16 | end 17 | 18 | it "should allow us to encode an in reply to field" do 19 | field = Mail::InReplyToField.new('<1234@test.lindsaar.net>') 20 | expect(field.encoded).to eq "In-Reply-To: <1234@test.lindsaar.net>\r\n" 21 | end 22 | 23 | it "should allow us to decode a message id field" do 24 | field = Mail::MessageIdField.new('<1234@test.lindsaar.net>') 25 | expect(field.decoded).to eq "<1234@test.lindsaar.net>" 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /spec/mail/fields/content_description_field_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::ContentDescriptionField do 5 | # Content-Description Header Field 6 | # 7 | # The ability to associate some descriptive information with a given 8 | # body is often desirable. For example, it may be useful to mark an 9 | # "image" body as "a picture of the Space Shuttle Endeavor." Such text 10 | # may be placed in the Content-Description header field. This header 11 | # field is always optional. 12 | # 13 | # description := "Content-Description" ":" *text 14 | # 15 | # The description is presumed to be given in the US-ASCII character 16 | # set, although the mechanism specified in RFC 2047 may be used for 17 | # non-US-ASCII Content-Description values. 18 | # 19 | 20 | describe "initialization" do 21 | 22 | it "should initialize" do 23 | expect { Mail::ContentDescriptionField.new("This is a description") }.not_to raise_error 24 | end 25 | 26 | it "should accept a string without the field name" do 27 | t = Mail::ContentDescriptionField.new('This is a description') 28 | expect(t.name).to eq 'Content-Description' 29 | expect(t.value).to eq 'This is a description' 30 | end 31 | 32 | end 33 | 34 | end 35 | -------------------------------------------------------------------------------- /spec/mail/fields/content_location_field_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::ContentLocationField do 5 | 6 | # Content-Location Header Field 7 | # 8 | describe "initialization" do 9 | 10 | it "should initialize" do 11 | expect { Mail::ContentLocationField.new("Content-Location", "7bit") }.not_to raise_error 12 | end 13 | 14 | it "should accept a string without the field name" do 15 | t = Mail::ContentLocationField.new('photo.jpg') 16 | expect(t.name).to eq 'Content-Location' 17 | expect(t.value).to eq 'photo.jpg' 18 | end 19 | 20 | it "should render an encoded field" do 21 | t = Mail::ContentLocationField.new('photo.jpg') 22 | expect(t.encoded).to eq "Content-Location: photo.jpg\r\n" 23 | end 24 | 25 | it "should render a decoded field" do 26 | t = Mail::ContentLocationField.new('photo.jpg') 27 | expect(t.decoded).to eq 'photo.jpg' 28 | end 29 | 30 | end 31 | 32 | describe "parsing the value" do 33 | 34 | it "should return an encoding string unquoted" do 35 | t = Mail::ContentLocationField.new('"A quoted filename.jpg"') 36 | expect(t.location).to eq 'A quoted filename.jpg' 37 | end 38 | 39 | end 40 | 41 | end 42 | -------------------------------------------------------------------------------- /spec/mail/fields/envelope_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::Envelope do 5 | # From RFC4155 The application/mbox Media Type 6 | # 7 | # o Each message in the mbox database MUST be immediately preceded 8 | # by a single separator line, which MUST conform to the following 9 | # syntax: 10 | # 11 | # The exact character sequence of "From"; 12 | # 13 | # a single Space character (0x20); 14 | # 15 | # the email address of the message sender (as obtained from the 16 | # message envelope or other authoritative source), conformant 17 | # with the "addr-spec" syntax from RFC 2822; 18 | # 19 | # a single Space character; 20 | # 21 | # a timestamp indicating the UTC date and time when the message 22 | # was originally received, conformant with the syntax of the 23 | # traditional UNIX 'ctime' output sans timezone (note that the 24 | # use of UTC precludes the need for a timezone indicator); 25 | # 26 | # an end-of-line marker. 27 | 28 | it "should initialize" do 29 | expect { Mail::Envelope.new('mikel@test.lindsaar.net Mon May 2 16:07:05 2005') }.not_to raise_error 30 | end 31 | 32 | describe "accessor methods" do 33 | it "should return the address" do 34 | envelope = Mail::Envelope.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") 35 | expect(envelope.from).to eq "mikel@test.lindsaar.net" 36 | end 37 | 38 | it "should return the date_time" do 39 | envelope = Mail::Envelope.new("mikel@test.lindsaar.net Mon Aug 17 00:39:21 2009") 40 | expect(envelope.date).to eq ::DateTime.parse("Mon Aug 17 00:39:21 2009") 41 | end 42 | end 43 | 44 | end 45 | -------------------------------------------------------------------------------- /spec/mail/fields/reply_to_field_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | # 5 | # reply-to = "Reply-To:" address-list CRLF 6 | # 7 | 8 | RSpec.describe Mail::ReplyToField do 9 | 10 | describe "initialization" do 11 | 12 | it "should initialize" do 13 | expect { Mail::ReplyToField.new("Mikel") }.not_to raise_error 14 | end 15 | 16 | it "should accept a string without the field name" do 17 | t = Mail::ReplyToField.new('Mikel Lindsaar , "Bob Smith" ') 18 | expect(t.name).to eq 'Reply-To' 19 | expect(t.value).to eq 'Mikel Lindsaar , "Bob Smith" ' 20 | end 21 | 22 | end 23 | 24 | describe "instance methods" do 25 | it "should return an address" do 26 | t = Mail::ReplyToField.new('Mikel Lindsaar ') 27 | expect(t.formatted).to eq ['Mikel Lindsaar '] 28 | end 29 | 30 | it "should return two addresses" do 31 | t = Mail::ReplyToField.new('Mikel Lindsaar , Ada Lindsaar ') 32 | expect(t.formatted.first).to eq 'Mikel Lindsaar ' 33 | expect(t.addresses.last).to eq 'ada@test.lindsaar.net' 34 | end 35 | 36 | it "should return one address and a group" do 37 | t = Mail::ReplyToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') 38 | expect(t.addresses[0]).to eq 'sam@me.com' 39 | expect(t.addresses[1]).to eq 'mikel@me.com' 40 | expect(t.addresses[2]).to eq 'bob@you.com' 41 | end 42 | 43 | it "should return the formatted line on to_s" do 44 | t = Mail::ReplyToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') 45 | expect(t.value).to eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' 46 | end 47 | 48 | it "should return the encoded line" do 49 | t = Mail::ReplyToField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') 50 | expect(t.encoded).to eq "Reply-To: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" 51 | end 52 | 53 | end 54 | 55 | 56 | end 57 | -------------------------------------------------------------------------------- /spec/mail/fields/resent_cc_field_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | # 5 | # resent-cc = "Resent-Cc:" address-list CRLF 6 | 7 | RSpec.describe Mail::ResentCcField do 8 | 9 | describe "initialization" do 10 | 11 | it "should initialize" do 12 | expect { Mail::ResentCcField.new("Mikel") }.not_to raise_error 13 | end 14 | 15 | it "should accept a string without the field name" do 16 | t = Mail::ResentCcField.new('Mikel Lindsaar , "Bob Smith" ') 17 | expect(t.name).to eq 'Resent-Cc' 18 | expect(t.value).to eq 'Mikel Lindsaar , "Bob Smith" ' 19 | end 20 | 21 | end 22 | 23 | describe "instance methods" do 24 | it "should return an address" do 25 | t = Mail::ResentCcField.new('Mikel Lindsaar ') 26 | expect(t.formatted).to eq ['Mikel Lindsaar '] 27 | end 28 | 29 | it "should return two addresses" do 30 | t = Mail::ResentCcField.new('Mikel Lindsaar , Ada Lindsaar ') 31 | expect(t.formatted.first).to eq 'Mikel Lindsaar ' 32 | expect(t.addresses.last).to eq 'ada@test.lindsaar.net' 33 | end 34 | 35 | it "should return one address and a group" do 36 | t = Mail::ResentCcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') 37 | expect(t.addresses[0]).to eq 'sam@me.com' 38 | expect(t.addresses[1]).to eq 'mikel@me.com' 39 | expect(t.addresses[2]).to eq 'bob@you.com' 40 | end 41 | 42 | it "should return the formatted line on to_s" do 43 | t = Mail::ResentCcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') 44 | expect(t.value).to eq 'sam@me.com, my_group: mikel@me.com, bob@you.com;' 45 | end 46 | 47 | it "should return the encoded line" do 48 | t = Mail::ResentCcField.new('sam@me.com, my_group: mikel@me.com, bob@you.com;') 49 | expect(t.encoded).to eq "Resent-Cc: sam@me.com, \r\n\smy_group: mikel@me.com, \r\n\sbob@you.com;\r\n" 50 | end 51 | 52 | end 53 | 54 | 55 | end 56 | -------------------------------------------------------------------------------- /spec/mail/fields/resent_date_field_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe Mail::ResentDateField do 6 | it "should initialize" do 7 | expect { Mail::ResentDateField.new("12 Aug 2009 00:00:02 GMT") }.not_to raise_error 8 | end 9 | 10 | it "should be able to tell the time" do 11 | expect(Mail::ResentDateField.new("12 Aug 2009 00:00:02 GMT").date_time.class).to eq DateTime 12 | end 13 | 14 | it "should accept a string without the field name" do 15 | t = Mail::ResentDateField.new('12 Aug 2009 00:00:02 GMT') 16 | expect(t.name).to eq 'Resent-Date' 17 | expect(t.value).to eq 'Wed, 12 Aug 2009 00:00:02 +0000' 18 | expect(t.date_time).to eq ::DateTime.parse('12 Aug 2009 00:00:02 GMT') 19 | end 20 | 21 | it "should give today's date if no date is specified" do 22 | now = DateTime.now 23 | expect(DateTime).to receive(:now).at_least(:once).and_return(now) 24 | t = Mail::ResentDateField.new 25 | expect(t.name).to eq 'Resent-Date' 26 | expect(t.date_time).to eq ::DateTime.parse(now.to_s) 27 | end 28 | 29 | end 30 | -------------------------------------------------------------------------------- /spec/mail/fields/resent_message_id_field_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe Mail::ResentMessageIdField do 6 | 7 | it "should initialize" do 8 | expect { Mail::ResentMessageIdField.new("<1234@test.lindsaar.net>") }.not_to raise_error 9 | end 10 | 11 | it "should accept a string without the field name" do 12 | t = Mail::ResentMessageIdField.new('<1234@test.lindsaar.net>') 13 | expect(t.name).to eq 'Resent-Message-ID' 14 | expect(t.value).to eq '<1234@test.lindsaar.net>' 15 | expect(t.message_id).to eq '1234@test.lindsaar.net' 16 | end 17 | 18 | it "should output lines shorter than 998 chars" do 19 | k = Mail::ResentMessageIdField.new(' ') 20 | lines = k.encoded.split("\r\n\s") 21 | lines.each { |line| expect(line.length).to be < 998 } 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /spec/mail/fields/resent_sender_field_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | # resent-sender = "Resent-Sender:" mailbox CRLF 6 | RSpec.describe Mail::ResentSenderField do 7 | let :field do 8 | Mail::ResentSenderField.new('Mikel Lindsaar ') 9 | end 10 | 11 | describe "initialization" do 12 | 13 | it "should initialize" do 14 | expect { Mail::ResentSenderField.new("Mikel") }.not_to raise_error 15 | end 16 | 17 | it "should accept a string without the field name" do 18 | t = Mail::ResentSenderField.new('Mikel Lindsaar , "Bob Smith" ') 19 | expect(t.name).to eq 'Resent-Sender' 20 | expect(t.value).to eq 'Mikel Lindsaar , "Bob Smith" ' 21 | end 22 | 23 | end 24 | 25 | it "formats the sender" do 26 | expect(field.formatted).to eq ['Mikel Lindsaar '] 27 | end 28 | 29 | it "parses a single sender address" do 30 | expect(field.address).to eq 'mikel@test.lindsaar.net' 31 | end 32 | 33 | it "returns the field value" do 34 | expect(field.value).to eq 'Mikel Lindsaar ' 35 | end 36 | 37 | it "encodes a header line" do 38 | expect(field.encoded).to eq "Resent-Sender: Mikel Lindsaar \r\n" 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /spec/mail/fields/return_path_field_spec.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | require 'spec_helper' 3 | 4 | RSpec.describe Mail::ReturnPathField do 5 | it "should allow you to specify a field" do 6 | rp = Mail::ReturnPathField.new('mikel@test.lindsaar.net') 7 | expect(rp.address).to eq 'mikel@test.lindsaar.net' 8 | end 9 | 10 | it "should encode the addr_spec in <>" do 11 | rp = Mail::ReturnPathField.new('mikel@test.lindsaar.net') 12 | expect(rp.encoded).to eq "Return-Path: \r\n" 13 | end 14 | 15 | it "should accept <>" do 16 | rp = Mail::ReturnPathField.new('<>') 17 | expect(rp.encoded).to eq "Return-Path: <>\r\n" 18 | end 19 | 20 | it "should set the return path" do 21 | mail = Mail.new do 22 | to "to@someemail.com" 23 | from "from@someemail.com" 24 | subject "Can't set the return-path" 25 | return_path "bounce@someemail.com" 26 | message_id "<1234@someemail.com>" 27 | body "body" 28 | end 29 | expect(mail.return_path).to eq "bounce@someemail.com" 30 | end 31 | 32 | it "should set the return path" do 33 | mail = Mail.new do 34 | to "to@someemail.com" 35 | from "from@someemail.com" 36 | subject "Can't set the return-path" 37 | return_path "bounce@someemail.com" 38 | message_id "<1234@someemail.com>" 39 | body "body" 40 | end 41 | encoded_mail = Mail.new(mail.encoded) 42 | expect(encoded_mail.return_path).to eq "bounce@someemail.com" 43 | end 44 | 45 | it "should wrap the return path addr_spec in <>" do 46 | mail = Mail.new do 47 | to "to@someemail.com" 48 | from "from@someemail.com" 49 | subject "Can't set the return-path" 50 | return_path "bounce@someemail.com" 51 | message_id "<1234@someemail.com>" 52 | body "body" 53 | end 54 | expect(mail.encoded).to match(//) 55 | end 56 | 57 | 58 | end 59 | -------------------------------------------------------------------------------- /spec/mail/fields/sender_field_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | # sender = "Sender:" mailbox CRLF 6 | RSpec.describe Mail::SenderField do 7 | let :field do 8 | Mail::SenderField.new('Mikel Lindsaar ') 9 | end 10 | 11 | describe "initialization" do 12 | it "should initialize" do 13 | expect { Mail::SenderField.new("Mikel") }.not_to raise_error 14 | end 15 | 16 | it "should accept a string without the field name" do 17 | t = Mail::SenderField.new('Mikel Lindsaar ') 18 | expect(t.name).to eq 'Sender' 19 | expect(t.value).to eq 'Mikel Lindsaar ' 20 | end 21 | 22 | it "should reject headers with multiple mailboxes" do 23 | pending 'Sender accepts an address list now, but should only accept a single address' 24 | expect { 25 | Mail::SenderField.new('Mikel Lindsaar , "Bob Smith" ') 26 | }.to raise_error(Mail::Field::ParseError) 27 | end 28 | end 29 | 30 | it "formats the sender" do 31 | expect(field.formatted).to eq ['Mikel Lindsaar '] 32 | end 33 | 34 | it "parses a single sender address" do 35 | expect(field.address).to eq 'mikel@test.lindsaar.net' 36 | end 37 | 38 | it "returns the field value" do 39 | expect(field.value).to eq 'Mikel Lindsaar ' 40 | end 41 | 42 | it "encodes a header line" do 43 | expect(field.encoded).to eq "Sender: Mikel Lindsaar \r\n" 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /spec/mail/fields/structured_field_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe Mail::StructuredField do 6 | 7 | describe "initialization" do 8 | 9 | it "should be instantiated" do 10 | expect {Mail::StructuredField.new("From", "bob@me.com")}.not_to raise_error 11 | end 12 | 13 | end 14 | 15 | describe "manipulation" do 16 | 17 | before(:each) do 18 | @field = Mail::StructuredField.new("From", "bob@me.com") 19 | end 20 | 21 | it "should allow us to set a text value at initialization" do 22 | expect{Mail::StructuredField.new("From", "bob@me.com")}.not_to raise_error 23 | end 24 | 25 | it "should provide access to the text of the field once set" do 26 | expect(@field.value).to eq "bob@me.com" 27 | end 28 | 29 | it "should provide a means to change the value" do 30 | @field.value = "bob@you.com" 31 | expect(@field.value).to eq "bob@you.com" 32 | end 33 | end 34 | 35 | describe "displaying encoded field and decoded value" do 36 | 37 | before(:each) do 38 | @field = Mail::FromField.new("bob@me.com") 39 | end 40 | 41 | it "should provide a to_s function that returns the decoded string" do 42 | expect(@field.to_s).to eq "bob@me.com" 43 | end 44 | 45 | it "should return '' on to_s if there is no value" do 46 | @field.value = nil 47 | expect(@field.encoded).to eq '' 48 | end 49 | 50 | it "should give an encoded value ready to insert into an email" do 51 | expect(@field.encoded).to eq "From: bob@me.com\r\n" 52 | end 53 | 54 | it "should return an empty string on encoded if it has no value" do 55 | @field.value = nil 56 | expect(@field.encoded).to eq '' 57 | end 58 | 59 | it "should return the field name and value in proper format when called to_s" do 60 | expect(@field.encoded).to eq "From: bob@me.com\r\n" 61 | end 62 | end 63 | end 64 | -------------------------------------------------------------------------------- /spec/mail/multibyte_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | require 'mail/multibyte/chars' 5 | 6 | RSpec.describe Mail::Multibyte::Chars do 7 | it "should upcase" do 8 | chars = described_class.new('Laurent, où sont les tests ?') 9 | expect(chars.upcase).to eq("LAURENT, OÙ SONT LES TESTS ?") 10 | end 11 | 12 | it "should downcase" do 13 | chars = described_class.new('VĚDA A VÝZKUM') 14 | expect(chars.downcase).to eq("věda a výzkum") 15 | end 16 | 17 | if 'string'.respond_to?(:force_encoding) 18 | it "doesn't mutate input string encoding" do 19 | s = 'ascii'.dup.force_encoding(Encoding::US_ASCII) 20 | described_class.new(s) 21 | expect(s.encoding).to eq(Encoding::US_ASCII) 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /spec/mail/round_tripping_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe "Round Tripping" do 6 | 7 | it "should round trip a basic email" do 8 | mail = Mail.new('Subject: FooBar') 9 | mail.body "This is Text" 10 | parsed_mail = Mail.new(mail.to_s) 11 | expect(parsed_mail.subject.to_s).to eq "FooBar" 12 | expect(parsed_mail.body.to_s).to eq "This is Text" 13 | end 14 | 15 | it "should round trip a html multipart email" do 16 | mail = Mail.new('Subject: FooBar') 17 | mail.text_part = Mail::Part.new do 18 | body "This is Text" 19 | end 20 | mail.html_part = Mail::Part.new do 21 | content_type "text/html; charset=US-ASCII" 22 | body "This is HTML" 23 | end 24 | parsed_mail = Mail.new(mail.to_s) 25 | expect(parsed_mail.mime_type).to eq 'multipart/alternative' 26 | expect(parsed_mail.boundary).to eq mail.boundary 27 | expect(parsed_mail.parts.length).to eq 2 28 | expect(parsed_mail.parts[0].body.to_s).to eq "This is Text" 29 | expect(parsed_mail.parts[1].body.to_s).to eq "This is HTML" 30 | end 31 | 32 | it "should round trip an email" do 33 | initial = Mail.new do 34 | to "mikel@test.lindsaar.net" 35 | subject "testing round tripping" 36 | body "Really testing round tripping." 37 | from "system@test.lindsaar.net" 38 | cc "nobody@test.lindsaar.net" 39 | bcc "bob@test.lindsaar.net" 40 | date Time.local(2009, 11, 6) 41 | add_file :filename => "foo.txt", :content => "I have \ntwo lines\n\n" 42 | end 43 | expect(Mail.new(initial.encoded).encoded).to eq initial.encoded 44 | end 45 | 46 | it "preserves text attachment newlines" do 47 | body = "I have \r\ntwo lines\n\r" 48 | initial = Mail.new 49 | initial.add_file :filename => "foo.txt", :content => body 50 | expect(Mail.new(initial.encoded).attachments.first.decoded).to eq ::Mail::Utilities.binary_unsafe_to_lf(body) 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /spec/mail/yaml_spec.rb: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | # frozen_string_literal: true 3 | require 'spec_helper' 4 | 5 | RSpec.describe Mail::YAML do 6 | 7 | describe "#load" do 8 | 9 | it 'loads YAML' do 10 | expect(Mail::YAML.load('{}')).to eq({}) 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /spec/matchers/break_down_to.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | module CustomMatchers 3 | class BreakDownTo 4 | def initialize(expected) 5 | @expected = expected 6 | end 7 | 8 | def matches?(target) 9 | @target = target 10 | @failed = false 11 | @expected.each_pair do |k,v| 12 | @failed = k unless @target.send(k) == @expected[k] 13 | end 14 | !@failed 15 | end 16 | 17 | def failure_message 18 | "expected #{@failed} to be |#{@expected[@failed]}| " + 19 | "but was |#{@target.send(@failed)}|" 20 | end 21 | 22 | def failure_message_when_negated 23 | "expected #{@failed} not to be |#{@expected[@failed]}| " + 24 | "and was |#{@target.send(@failed)}|" 25 | end 26 | 27 | end 28 | 29 | # Actual matcher that is exposed. 30 | def break_down_to(expected) 31 | BreakDownTo.new(expected) 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /tools/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'rubygems' 3 | require 'bundler/setup' 4 | 5 | begin 6 | require 'byebug' 7 | rescue LoadError 8 | end 9 | 10 | require 'mail' 11 | 12 | require 'irb' 13 | require 'irb/completion' 14 | IRB.start 15 | --------------------------------------------------------------------------------