Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Colorize examples in README.md #18

Merged
merged 2 commits into from
Jan 25, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
258 changes: 146 additions & 112 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,10 @@ To quickly validate email addresses, use the valid? and error helpers.
`valid?` returns a boolean, and `error` returns nil if valid, otherwise
a basic error message.

EmailAddress.valid? "[email protected]" #=> true
EmailAddress.error "[email protected]" #=> "Invalid Host/Domain Name"
```ruby
EmailAddress.valid? "[email protected]" #=> true
EmailAddress.error "[email protected]" #=> "Invalid Host/Domain Name"
```

`EmailAddress` deeply validates your email addresses. It checks:

Expand All @@ -48,14 +50,17 @@ website on one provider (ISP, Heroku, etc.), and email on a different
provider (such as Google Apps). Note that `example.com`, while
a valid domain name, does not have MX records.

EmailAddress.valid? "[email protected]" #=> false
EmailAddress.valid? "[email protected]", host_validation: :syntax #=> true
```ruby
EmailAddress.valid? "[email protected]" #=> false
EmailAddress.valid? "[email protected]", host_validation: :syntax #=> true
```

Most mail servers do not yet support Unicode mailboxes, so the default here is ASCII.

EmailAddress.error "Pelé@google.com" #=> "Invalid Recipient/Mailbox"
EmailAddress.valid? "Pelé@google.com", local_encoding: :unicode #=> true

```ruby
EmailAddress.error "Pelé@google.com" #=> "Invalid Recipient/Mailbox"
EmailAddress.valid? "Pelé@google.com", local_encoding: :unicode #=> true
```

## Background

Expand Down Expand Up @@ -186,8 +191,10 @@ If you are not using Bundler, you need to install the gem yourself.

Require the gem inside your script.

require 'rubygems'
require 'email_address'
```ruby
require 'rubygems'
require 'email_address'
```

## Usage

Expand All @@ -197,41 +204,47 @@ instantiate an object to inspect the address.
These top-level helpers return edited email addresses and validation
check.

address = "[email protected]"
EmailAddress.valid?(address) #=> true
EmailAddress.normal(address) #=> "[email protected]"
EmailAddress.canonical(address) #=> "[email protected]"
EmailAddress.reference(address) #=> "c5be3597c391169a5ad2870f9ca51901"
EmailAddress.redact(address) #=> "{bea3f3560a757f8142d38d212a931237b218eb5e}@gmail.com"
EmailAddress.munge(address) #=> "cl*****@gm*****"
EmailAddress.matches?(address, 'google') #=> 'google' (true)
EmailAddress.error("#[email protected]") #=> "Invalid Mailbox"
```ruby
address = "[email protected]"
EmailAddress.valid?(address) #=> true
EmailAddress.normal(address) #=> "[email protected]"
EmailAddress.canonical(address) #=> "[email protected]"
EmailAddress.reference(address) #=> "c5be3597c391169a5ad2870f9ca51901"
EmailAddress.redact(address) #=> "{bea3f3560a757f8142d38d212a931237b218eb5e}@gmail.com"
EmailAddress.munge(address) #=> "cl*****@gm*****"
EmailAddress.matches?(address, 'google') #=> 'google' (true)
EmailAddress.error("#[email protected]") #=> "Invalid Mailbox"
```

Or you can create an instance of the email address to work with it.

email = EmailAddress.new(address) #=> #<EmailAddress::Address:0x007fe6ee150540 ...>
email.normal #=> "[email protected]"
email.canonical #=> "[email protected]"
email.original #=> "[email protected]"
email.valid? #=> true
```ruby
email = EmailAddress.new(address) #=> #<EmailAddress::Address:0x007fe6ee150540 ...>
email.normal #=> "[email protected]"
email.canonical #=> "[email protected]"
email.original #=> "[email protected]"
email.valid? #=> true
```

Here are some other methods that are available.

email.redact #=> "{bea3f3560a757f8142d38d212a931237b218eb5e}@gmail.com"
email.sha1 #=> "bea3f3560a757f8142d38d212a931237b218eb5e"
email.md5 #=> "c5be3597c391169a5ad2870f9ca51901"
email.host_name #=> "gmail.com"
email.provider #=> :google
email.mailbox #=> "clark.kent"
email.tag #=> "scoops"
```ruby
email.redact #=> "{bea3f3560a757f8142d38d212a931237b218eb5e}@gmail.com"
email.sha1 #=> "bea3f3560a757f8142d38d212a931237b218eb5e"
email.md5 #=> "c5be3597c391169a5ad2870f9ca51901"
email.host_name #=> "gmail.com"
email.provider #=> :google
email.mailbox #=> "clark.kent"
email.tag #=> "scoops"

email.host.exchanger.first[:ip] #=> "2a00:1450:400b:c02::1a"
email.host.txt_hash #=> {:v=>"spf1", :redirect=>"\_spf.google.com"}
email.host.exchanger.first[:ip] #=> "2a00:1450:400b:c02::1a"
email.host.txt_hash #=> {:v=>"spf1", :redirect=>"\_spf.google.com"}

EmailAddress.normal("HIRO@こんにちは世界.com")
#=> "[email protected]"
EmailAddress.normal("[email protected]", host_encoding: :unicode)
#=> "hiro@こんにちは世界.com"
EmailAddress.normal("HIRO@こんにちは世界.com")
#=> "[email protected]"
EmailAddress.normal("[email protected]", host_encoding: :unicode)
#=> "hiro@こんにちは世界.com"
```

#### Rails Validator

Expand All @@ -240,9 +253,11 @@ Specify your email address attributes with `field: :user_email`, or
`fields: [:email1, :email2]`. If neither is given, it assumes to use the
`email` or `email_address` attribute.

class User < ActiveRecord::Base
validates_with EmailAddress::ActiveRecordValidator, field: :email
end
```ruby
class User < ActiveRecord::Base
validates_with EmailAddress::ActiveRecordValidator, field: :email
end
```

#### Rails Email Address Type Attribute

Expand All @@ -252,9 +267,11 @@ First, you need to register the type in
`config/initializers/email_address.rb` along with any global
configurations you want.

ActiveRecord::Type.register(:email_address, EmailAddress::EmailAddressType)
ActiveRecord::Type.register(:canonical_email_address,
EmailAddress::CanonicalEmailAddressType)
```ruby
ActiveRecord::Type.register(:email_address, EmailAddress::EmailAddressType)
ActiveRecord::Type.register(:canonical_email_address,
EmailAddress::CanonicalEmailAddressType)
```

Assume the Users table contains the columns "email" and "canonical_email".
We want to normalize the address in "email" and store the canonical/unique
Expand All @@ -263,39 +280,42 @@ the email attribute is assigned. With the canonical_email column,
we can look up the User, even it the given email address didn't exactly
match the registered version.

class User < ApplicationRecord
attribute :email, :email_address
attribute :canonical_email, :canonical_email_address

validates_with EmailAddress::ActiveRecordValidator,
fields: %i(email canonical_email)

def email=(email_address)
self[:canonical_email] = email_address
self[:email] = email_address
end

def self.find_by_email(email)
user = self.find_by(email: EmailAddress.normal(email))
user ||= self.find_by(canonical_email: EmailAddress.canonical(email))
user ||= self.find_by(canonical_email: EmailAddress.redacted(email))
user
end

def redact!
self[:canonical_email] = EmailAddress.redact(self.canonical_email)
self[:email] = self[:canonical_email]
end
end
```ruby
class User < ApplicationRecord
attribute :email, :email_address
attribute :canonical_email, :canonical_email_address

validates_with EmailAddress::ActiveRecordValidator,
fields: %i(email canonical_email)

def email=(email_address)
self[:canonical_email] = email_address
self[:email] = email_address
end

def self.find_by_email(email)
user = self.find_by(email: EmailAddress.normal(email))
user ||= self.find_by(canonical_email: EmailAddress.canonical(email))
user ||= self.find_by(canonical_email: EmailAddress.redacted(email))
user
end

def redact!
self[:canonical_email] = EmailAddress.redact(self.canonical_email)
self[:email] = self[:canonical_email]
end
end
```

Here is how the User model works:

user = User.create(email:"[email protected]")
user.email #=> "[email protected]"
user.canonical_email #=> "[email protected]"
User.find_by_email("[email protected]")
#=> #<User email="[email protected]">

```ruby
user = User.create(email:"[email protected]")
user.email #=> "[email protected]"
user.canonical_email #=> "[email protected]"
User.find_by_email("[email protected]")
#=> #<User email="[email protected]">
```

The `find_by_email` method looks up a given email address by the
normalized form (lower case), then by the canonical form, then finally
Expand All @@ -318,17 +338,19 @@ which syntax and network validations to perform.

You can compare email addresses:

e1 = EmailAddress.new("[email protected]")
e2 = EmailAddress.new("[email protected]")
e3 = EmailAddress.new(e2.redact)
e1.to_s #=> "[email protected]"
e2.to_s #=> "[email protected]"
e3.to_s #=> "{bea3f3560a757f8142d38d212a931237b218eb5e}@gmail.com"
```ruby
e1 = EmailAddress.new("[email protected]")
e2 = EmailAddress.new("[email protected]")
e3 = EmailAddress.new(e2.redact)
e1.to_s #=> "[email protected]"
e2.to_s #=> "[email protected]"
e3.to_s #=> "{bea3f3560a757f8142d38d212a931237b218eb5e}@gmail.com"

e1 == e2 #=> false (Matches by normalized address)
e1.same_as?(e2) #=> true (Matches as canonical address)
e1.same_as?(e3) #=> true (Matches as redacted address)
e1 < e2 #=> true (Compares using normalized address)
e1 == e2 #=> false (Matches by normalized address)
e1.same_as?(e2) #=> true (Matches as canonical address)
e1.same_as?(e3) #=> true (Matches as redacted address)
e1 < e2 #=> true (Compares using normalized address)
```

#### Matching

Expand All @@ -345,40 +367,50 @@ Matching addresses by simple patterns:

Usage:

e = EmailAddress.new("[email protected]")
e.matches?("gmail.com") #=> true
e.matches?("google") #=> true
e.matches?(".org") #=> false
e.matches?("g*com") #=> true
e.matches?("gmail.") #=> true
e.matches?("*kent*@") #=> true
```ruby
e = EmailAddress.new("[email protected]")
e.matches?("gmail.com") #=> true
e.matches?("google") #=> true
e.matches?(".org") #=> false
e.matches?("g*com") #=> true
e.matches?("gmail.") #=> true
e.matches?("*kent*@") #=> true
```

### Configuration

You can pass an options hash on the `.new()` and helper class methods to
control how the library treats that address. These can also be
configured during initialization by provider and default (see below).

EmailAddress.new("[email protected]",
host_validation: :syntax, host_encoding: :unicode)
```ruby
EmailAddress.new("[email protected]",
host_validation: :syntax, host_encoding: :unicode)
```

Globally, you can change and query configuration options:

EmailAddress::Config.setting(:host_validation, :mx)
EmailAddress::Config.setting(:host_validation) #=> :mx
```ruby
EmailAddress::Config.setting(:host_validation, :mx)
EmailAddress::Config.setting(:host_validation) #=> :mx
```

Or set multiple settings at once:

EmailAddress::Config.configure(local_downcase:false, host_validation: :syntax)
```ruby
EmailAddress::Config.configure(local_downcase: false, host_validation: :syntax)
```

You can add special rules by domain or provider. It takes the options
above and adds the :domain_match and :exchanger_match rules.

EmailAddress.define_provider('google',
domain_match: %w(gmail.com googlemail.com),
exchanger_match: %w(google.com), # Requires host_validation==:mx
local_size: 5..64,
mailbox_canonical: ->(m) {m.gsub('.','')})
```ruby
EmailAddress.define_provider('google',
domain_match: %w(gmail.com googlemail.com),
exchanger_match: %w(google.com), # Requires host_validation==:mx
local_size: 5..64,
mailbox_canonical: ->(m) {m.gsub('.','')})
```

The library ships with the most common set of provider rules. It is not meant
to house a database of all providers, but a separate `email_address-providers`
Expand All @@ -396,26 +428,29 @@ DNS. If you specify an exchanger pattern, but requires a DNS MX lookup.
For Rails application, create an initializer file with your default
configuration options:

# ./config/initializers/email_address.rb
EmailAddress::Config.setting( local_format: :relaxed )
EmailAddress::Config.provider(:github,
host_match: %w(github.com), local_format: :standard)
```ruby
# ./config/initializers/email_address.rb
EmailAddress::Config.setting( local_format: :relaxed )
EmailAddress::Config.provider(:github,
host_match: %w(github.com), local_format: :standard)
```

#### Override Error Messaegs

You can override the default error messages as follows:

EmailAddress::Config.error_messages(
invalid_address: "Invalid Email Address",
invalid_mailbox: "Invalid Recipient/Mailbox",
invalid_host: "Invalid Host/Domain Name",
exceeds_size: "Address too long",
not_allowed: "Address is not allowed",
incomplete_domain: "Domain name is incomplete")
```ruby
EmailAddress::Config.error_messages(
invalid_address: "Invalid Email Address",
invalid_mailbox: "Invalid Recipient/Mailbox",
invalid_host: "Invalid Host/Domain Name",
exceeds_size: "Address too long",
not_allowed: "Address is not allowed",
incomplete_domain: "Domain name is incomplete")
```

Full translation support would be ideal though.


### Available Configuration Settings

* sha1_secret -
Expand Down Expand Up @@ -518,7 +553,6 @@ Proper personal identity can still be provided using
[MIME Encoded-Words](http://en.wikipedia.org/wiki/MIME#Encoded-Word)
in Email headers.


#### Email Addresses as Sensitive Data

Like Social Security and Credit Card Numbers, email addresses are
Expand Down