Skip to content

Commit

Permalink
Merge pull request #7 from SparkPost/style
Browse files Browse the repository at this point in the history
Address review issues (#6)
  • Loading branch information
richleland committed Jan 21, 2016
2 parents 943d6c8 + 4961768 commit c7ec15f
Show file tree
Hide file tree
Showing 28 changed files with 634 additions and 183 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
## Change Log

### v0.0.1 (2016/01/21)
- First release

67 changes: 67 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Contributing to elixir-sparkpost

Transparency is one of our core values, and we encourage developers to contribute and become part of the SparkPost developer community.

The following is a set of guidelines for contributing to elixir-sparkpost,
which is hosted in the [SparkPost Organization](https://github.com/sparkpost) on GitHub.
These are just guidelines, not rules, use your best judgment and feel free to
propose changes to this document in a pull request.

## Submitting Issues

* Before logging an issue, please [search existing issues](https://github.com/SparkPost/elixir-sparkpost/issues?q=is%3Aissue+is%3Aopen) first.

* You can create an issues [here](https://github.com/SparkPost/elixir-sparkpost/issues/new). Please include the library version number and as much detail as possible in your report.

You can grab the library version number like this: `mix deps | grep sparkpost`

## Local Development

1. Fork this repo
1. Clone your fork
1. Write some code!
1. Retrieve dependencies: `mix deps.get`
1. To run the test suite: `mix test`
1. To check test code coverage: `mix coveralls`
1. To check coding standards: `mix credo`
1. To generate reference docs: `mix docs`
1. Please follow the pull request submission steps in the next section

## Contribution Steps

- We follow this community [Elixir Style Guide](https://github.com/niftyn8/elixir_style_guide).
- We strive for 100% test coverage.
- We include @moduledoc and @doc content (almost) everywhere.

To contribute to elixir-sparkpost:

1. Create a new branch named after the issue you’ll be fixing (include the issue number as the branch name, example: Issue in GH is #8 then the branch name should be ISSUE-8))
1. Write corresponding tests and code (only what is needed to satisfy the issue and tests please)
* Include your tests in the 'test' directory in an appropriate test file
* Write code to satisfy the tests
1. Ensure automated tests (`mix test`) pass
1. Submit a new Pull Request applying your feature/fix branch to the `master` branch

### Releasing

Check out these general [docs on publishing packages](https://hex.pm/docs/publish) to Hex.

To publish a new release:

1. Update `package` metadata in mix.exs:
* bump the version number
* add new files you want to distribute

```elixir
defp package do
[
version: "0.0.1", # <-- bump this
files: [
"lib", "mix.exs", "README.md", "CONTRIBUTING.md" # <-- add new files for distro here
],
]
end
```

3. When you're ready, publish to Hex: `mix hex.publish`

46 changes: 28 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,40 @@

[![Travis CI](https://travis-ci.org/SparkPost/elixir-sparkpost.svg?branch=master)](https://travis-ci.org/SparkPost/elixir-sparkpost) [![Coverage Status](https://coveralls.io/repos/SparkPost/elixir-sparkpost/badge.svg?branch=master&service=github)](https://coveralls.io/github/SparkPost/elixir-sparkpost?branch=master)

The official [Elixir](http://elixir-lang.org/) package for using the [SparkPost API](https://www.sparkpost.com/api).
The official [Elixir](http://elixir-lang.org/) package for the [SparkPost API](https://www.sparkpost.com/api).

Capabilities include:
- convenience functions for easy "I just want to send mail" users
- advanced functions for unleashing all of Sparkpost's capabilities

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed as:

1. Add sparkpost to your list of dependencies in `mix.exs`:

def deps do
[{:sparkpost, "~> 0.0.1"}]
end
```elixir
def deps do
[{:sparkpost, "~> 0.0.1"}]
end
```

2. Ensure sparkpost is started before your application:

def application do
[applications: [:sparkpost]]
end
```elixir
def application do
[applications: [:sparkpost]]
end
```

3. Update your dependencies:

```bash
$ mix deps.get
```

## Usage

### Configuration

In your config/config.exs file:

```elixir
Expand All @@ -54,17 +64,15 @@ end

```elixir
defmodule MyApp.Example do
alias SparkPost.Transmission
alias SparkPost.Recipient
alias SparkPost.Template

def send_message do
Transmission.create(%Transmission{
recipients: [ %Recipient{ address: %Sparkpost.Address{ email: "[email protected]" }} ],
alias SparkPost.{Content, Recipient, Transmission}

def send_message do
Transmission.send(%Transmission{
recipients: [ "[email protected]" ],
return_path: "[email protected]",
content: %Template.Inline{
content: %Content.Inline{
subject: "Sending email from Elixir is awesome!",
from: %Sparkpost.Address{ email: "[email protected]" },
from: "[email protected]",
text: "Hi there!",
html: "<p>Hi there!</p>"
}
Expand All @@ -83,6 +91,8 @@ Start your app and send a message:

### Contribute

We welcome your contributions! See [CONTRIBUTING.md](CONTRIBUTING.md) for details on how to help out.

### Change Log

[See ChangeLog here](CHANGELOG.md)
9 changes: 4 additions & 5 deletions examples/attachment.exs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
from = "me@here.com"
to = "you@there.com"
from = "elixir@sparkpostbox.com"
to = "ewan.dennis@sparkpost.com"
filename = "test/data/sparky.png"

SparkPost.Transmission.create(
SparkPost.Transmission.send(
%SparkPost.Transmission{
options: %SparkPost.Transmission.Options{},
recipients: SparkPost.Recipient.to_recipient_list([to]),
recipients: [to],
return_path: from,
content: %SparkPost.Content.Inline{
from: from,
Expand Down
4 changes: 2 additions & 2 deletions examples/simplesend.exs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
to = "[email protected]"
from = "me@here.com"
from = "Elixir SparkPost <elixir@sparkpostbox.com>"
SparkPost.send(
to: to,
from: from,
subject: "My first Elixir email",
text: "This is the boring version of the email body",
html: "This is the <strong>tasty</strong> <em>rich</em> version of the <a href=\"https://www.sparkpost.com/\">email</a> body."
)
)
33 changes: 31 additions & 2 deletions lib/address.ex
Original file line number Diff line number Diff line change
@@ -1,11 +1,40 @@
defmodule SparkPost.Address do
@moduledoc """
An long-form email address with both name and address parts.
e.g.: Sparky McSparkPost <[email protected]>
Designed for use in:
- `%SparkPost.Content.Inline{from: ...}`
- `%SparkPost.Recipient.address{from: ...}`
"""

defstruct name: nil, email: :required

@doc """
Convenience conversions to `%SparkPost.Address{}` from:
- email address string
- `%{name: ..., email: ...}`
"""
def to_address(email) when is_binary(email) do
parse_address(email)
end

def to_address(%{name: name, email: email})do
%__MODULE__{name: name, email: email}
end

def to_address(%{email: email})do
%__MODULE__{email: email}
end

def to_address(struc) when is_map(struc) do
struct(__MODULE__, struc)
defp parse_address(addr) when is_binary(addr) do
case Regex.run(~r/\s*(.+)\s+<(.+@.+)>\s*$/, addr) do
[_, name, email] -> %__MODULE__{ name: name, email: email }
nil -> case Regex.run(~r/\s*(.+@.+)\s*$/, addr) do
[_, email] -> %__MODULE__{ email: email }
nil -> raise __MODULE__.FormatError, message: "Invalid email address: #{addr}"
end
end
end
end
9 changes: 9 additions & 0 deletions lib/address/error.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
defmodule SparkPost.Address.FormatError do
@moduledoc """
Raised by Address.to_address/1 when an invalid email address is detected.
## Fields
- message: human-readable error message
"""
defexception message: nil
end
15 changes: 15 additions & 0 deletions lib/attachment.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
defmodule SparkPost.Content.Attachment do
@moduledoc """
File attachment.
Designed for use in `%SparkPost.Content.Inline{attachments: ...}` and
`%SparkPost.Content.Inline{inline_images: ...}`.
## Fields
- name: filename
- type: MIME type
- data: binary file content
"""

defstruct name: :required, type: :required, data: :required
end
68 changes: 49 additions & 19 deletions lib/content.ex
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
defmodule SparkPost.Content do
defmodule Inline do
defstruct from: :required,
subject: :required,
text: nil,
html: nil,
reply_to: nil,
headers: nil,
attachments: nil,
inline_images: nil
end
@moduledoc """
Various message content representations.
defmodule Raw do
defstruct email_rfc822: :required
end
Designed for use in `%SparkPost.Transmission{content: ...}`.
defmodule TemplateRef do
defstruct template_id: :required, use_draft_template: nil
end
See submodules for concrete structs:
- `SparkPost.Content.Inline`
- `SparkPost.Content.Raw`
- `SparkPost.Content.TemplateRef`
"""

defmodule Attachment do
defstruct name: :required, type: :required, data: :required
end
@doc """
Create a %SparkPost.Content.Attachment from raw fields.
## Example
SparkPost.Content.to_attachment("bob.jpg", "image/jpeg", File.read!("bob.jpg"))
#=> %SparkPost.Content.Attachment{name: "bob.jpg", type: "image/jpeg", data: "iVBORw0KGgo..."}
"""
def to_attachment(name, type, data) when is_binary(data) do
%SparkPost.Content.Attachment{
name: name,
Expand All @@ -30,6 +25,36 @@ defmodule SparkPost.Content do
}
end

@doc ~S"""
Convenience conversions:
- %{email_rc822: ...} -> %SparkPost.Content.Raw
- %{template_id: ..., use_draft_template: ...} -> %SparkPost.Content.TemplateRef
- %{...} -> %SparkPost.Content.Inline
## Examples
Raw content:
SparkPost.Content.to_content(%{email_rfc822: "Content-Type: text/plain\r\nTo: \"{{address.name}}\" <{{address.email}}>\r\n\r\nThis message came from Elixir\r\n"})
#=> %SparkPost.Content.Raw{email_rfc822: "Content-Type: text/plain\r\nTo: \"{{address.name}}\" <{{address.email}}>\r\n\r\nThis message came from Elixir\r\n"}
Stored template:
SparkPost.Content.to_content(%{
template_id: "template-101",
use_draft_template: true
})
#=> %SparkPost.Content.TemplateRef{template_id: "template-101", use_draft_template: true}
Inline content:
Sparkpost.Content.to_content(%{
from: "[email protected]",
subject: "Elixir rocks",
text: "A simple little message"
})
#=> %SparkPost.Content.Inline{
from: "[email protected]",
subject: "Elixir rocks",
text: "A simple little message"
}
"""
def to_content(%{email_rfc822: email_rfc822}) do
%SparkPost.Content.Raw{email_rfc822: email_rfc822}
end
Expand All @@ -38,6 +63,11 @@ defmodule SparkPost.Content do
%SparkPost.Content.TemplateRef{template_id: template_id, use_draft_template: draft_flag}
end

def to_content(%SparkPost.Content.Inline{} = content) do
%{ content |
from: SparkPost.Address.to_address(content.from)}
end

def to_content(content) when is_map(content) do
%{ struct(SparkPost.Content.Inline, content) |
from: SparkPost.Address.to_address(content.from)}
Expand Down
28 changes: 28 additions & 0 deletions lib/content/inline.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
defmodule SparkPost.Content.Inline do
@moduledoc """
Inline message content.
Designed for use in `%SparkPost.Transmission{content: ...}`.
## Fields
- from: 'From' address (email string | `%SparkPost.Address`)
- reply_to: the destination for replies to this message aka `Reply-To` (email string)
- headers: email headers (map)
- subject: email subject line
- text: plain text message body
- html: HTML-formatted message body
- attachments: file attachments (list of `%SparkPost.Content.Attachment`)
- inline_images: inline images (list of `%SparkPost.Content.Attachment`)
Note: at least one of `text` or `html` must be filled out.
"""

defstruct from: :required,
reply_to: nil,
headers: nil,
subject: :required,
text: nil,
html: nil,
attachments: nil,
inline_images: nil
end
12 changes: 12 additions & 0 deletions lib/content/raw.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
defmodule SparkPost.Content.Raw do
@moduledoc """
Raw message content, formatted as per [RFC2822](http://www.faqs.org/rfcs/rfc822.html).
Designed for use in `%SparkPost.Transmission{content: ...}`.
## Fields
- email_rfc822: raw message body
"""

defstruct email_rfc822: :required
end
Loading

0 comments on commit c7ec15f

Please sign in to comment.