Commit 24f9f8ce225a95a38286f57c46bf2982b8062372
0 parents
Exists in
master
fork from github
Showing
13 changed files
with
331 additions
and
0 deletions
Show diff stats
1 | +++ a/.gitignore | |
... | ... | @@ -0,0 +1,44 @@ |
1 | +*.rbc | |
2 | +capybara-*.html | |
3 | +.rspec | |
4 | +/log | |
5 | +/tmp | |
6 | +/db/*.sqlite3 | |
7 | +/db/*.sqlite3-journal | |
8 | +/public/system | |
9 | +/coverage/ | |
10 | +/spec/tmp | |
11 | +**.orig | |
12 | +rerun.txt | |
13 | +pickle-email-*.html | |
14 | + | |
15 | +# TODO Comment out these rules if you are OK with secrets being uploaded to the repo | |
16 | +config/initializers/secret_token.rb | |
17 | +config/secrets.yml | |
18 | + | |
19 | +# dotenv | |
20 | +# TODO Comment out this rule if environment variables can be committed | |
21 | +.env | |
22 | + | |
23 | +## Environment normalization: | |
24 | +/.bundle | |
25 | +/vendor/bundle | |
26 | + | |
27 | +# these should all be checked in to normalize the environment: | |
28 | +# Gemfile.lock, .ruby-version, .ruby-gemset | |
29 | + | |
30 | +# unless supporting rvm < 1.11.0 or doing something fancy, ignore this: | |
31 | +.rvmrc | |
32 | + | |
33 | +# if using bower-rails ignore default bower_components path bower.json files | |
34 | +/vendor/assets/bower_components | |
35 | +*.bowerrc | |
36 | +bower.json | |
37 | + | |
38 | +# Ignore pow environment settings | |
39 | +.powenv | |
40 | + | |
41 | +# Ignore Byebug command history file. | |
42 | +.byebug_history | |
43 | + | |
44 | +.*.swp | ... | ... |
1 | +++ a/LICENSE | |
... | ... | @@ -0,0 +1,21 @@ |
1 | +The MIT License (MIT) | |
2 | + | |
3 | +Copyright (c) 2016 Towon Zhou | |
4 | + | |
5 | +Permission is hereby granted, free of charge, to any person obtaining a copy | |
6 | +of this software and associated documentation files (the "Software"), to deal | |
7 | +in the Software without restriction, including without limitation the rights | |
8 | +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
9 | +copies of the Software, and to permit persons to whom the Software is | |
10 | +furnished to do so, subject to the following conditions: | |
11 | + | |
12 | +The above copyright notice and this permission notice shall be included in all | |
13 | +copies or substantial portions of the Software. | |
14 | + | |
15 | +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
16 | +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
17 | +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
18 | +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
19 | +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
20 | +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
21 | +SOFTWARE. | ... | ... |
1 | +++ a/MIT-LICENSE | |
... | ... | @@ -0,0 +1,20 @@ |
1 | +Copyright 2016 Towon Zhou | |
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 | |
17 | +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE | |
18 | +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION | |
19 | +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION | |
20 | +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | ... | ... |
1 | +++ a/README.md | |
... | ... | @@ -0,0 +1,36 @@ |
1 | +# sendcloud_rails | |
2 | + | |
3 | +Thanks for jorgemanrubia("https://github.com/jorgemanrubia/mailgun_rails") | |
4 | + | |
5 | +*sendcloud_rails* is an Action Mailer adapter for using [Sendcloud](http://sendcloud.sohu.com/) in Rails apps. It uses the [Sendcloud HTTP API](http://sendcloud.sohu.com/doc/email_v2/code/#ruby) internally. | |
6 | + | |
7 | +## Installing | |
8 | + | |
9 | +In your `Gemfile` | |
10 | + | |
11 | +```ruby | |
12 | +gem 'sendcloud_rails' | |
13 | +``` | |
14 | + | |
15 | +## Usage | |
16 | + | |
17 | +To configure your sendcloud credentials place the following code in the corresponding environment file (`development.rb`, `production.rb`...) | |
18 | + | |
19 | +```ruby | |
20 | +config.action_mailer.delivery_method = :sendcloud | |
21 | +config.action_mailer.sendcloud_settings = { | |
22 | + api_user: '<apiUser>', | |
23 | + api_key: '<apiKey>', | |
24 | + api_url: 'http://api.sendcloud.net/apiv2/mail/send' | |
25 | +} | |
26 | +``` | |
27 | + | |
28 | +Now you can send emails using plain Action Mailer: | |
29 | + | |
30 | +```ruby | |
31 | +email = mail from: 'sender@email.com', to: 'receiver@email.com', subject: 'this is an email' | |
32 | +``` | |
33 | + | |
34 | +Pull requests are welcomed | |
35 | + | |
36 | + | ... | ... |
1 | +++ a/Rakefile | |
... | ... | @@ -0,0 +1,23 @@ |
1 | +begin | |
2 | + require 'bundler/setup' | |
3 | +rescue LoadError | |
4 | + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' | |
5 | +end | |
6 | + | |
7 | +require 'rdoc/task' | |
8 | + | |
9 | +RDoc::Task.new(:rdoc) do |rdoc| | |
10 | + rdoc.rdoc_dir = 'rdoc' | |
11 | + rdoc.title = 'Rails' | |
12 | + rdoc.options << '--line-numbers' | |
13 | + rdoc.rdoc_files.include('README.rdoc') | |
14 | + rdoc.rdoc_files.include('lib/**/*.rb') | |
15 | +end | |
16 | + | |
17 | +Bundler::GemHelper.install_tasks | |
18 | + | |
19 | +require 'rspec/core/rake_task' | |
20 | + | |
21 | +RSpec::Core::RakeTask.new(:spec) | |
22 | + | |
23 | +task default: :spec | ... | ... |
1 | +++ a/lib/sendcloud/client.rb | |
... | ... | @@ -0,0 +1,19 @@ |
1 | +require 'rest_client' | |
2 | + | |
3 | +module Sendcloud | |
4 | + class Client | |
5 | + attr_reader :api_url | |
6 | + | |
7 | + def initialize(api_url) | |
8 | + @api_url = api_url | |
9 | + end | |
10 | + | |
11 | + def send_message(options) | |
12 | + RestClient.post sendcloud_url, options | |
13 | + end | |
14 | + | |
15 | + def sendcloud_url | |
16 | + @api_url | |
17 | + end | |
18 | + end | |
19 | +end | ... | ... |
1 | +++ a/lib/sendcloud/deliverer.rb | |
... | ... | @@ -0,0 +1,114 @@ |
1 | +module Sendcloud | |
2 | + class Deliverer | |
3 | + | |
4 | + attr_accessor :settings | |
5 | + | |
6 | + def initialize(settings) | |
7 | + self.settings = settings | |
8 | + end | |
9 | + | |
10 | + def api_user | |
11 | + self.settings[:api_user] | |
12 | + end | |
13 | + | |
14 | + def api_key | |
15 | + self.settings[:api_key] | |
16 | + end | |
17 | + | |
18 | + def api_url | |
19 | + self.settings[:api_url] | |
20 | + end | |
21 | + | |
22 | + def deliver!(rails_message) | |
23 | + options = build_sendcloud_message_for(rails_message) | |
24 | + response = sendcloud_client.send_message options | |
25 | + Rails.logger.info("from:#{options[:from]} to:#{options[:to]} res:#{response}") | |
26 | + if response.code == 200 | |
27 | + sendcloud_message_id = JSON.parse(response.to_str)["id"] | |
28 | + rails_message.message_id = sendcloud_message_id | |
29 | + end | |
30 | + response | |
31 | + end | |
32 | + | |
33 | + private | |
34 | + | |
35 | + def build_sendcloud_message_for(rails_message) | |
36 | + sendcloud_message = build_basic_sendcloud_message_for rails_message | |
37 | + transform_sendcloud_attributes_from_rails rails_message, sendcloud_message | |
38 | + remove_empty_values sendcloud_message | |
39 | + | |
40 | + sendcloud_message | |
41 | + end | |
42 | + | |
43 | + def build_basic_sendcloud_message_for(rails_message) | |
44 | + sendcloud_message = { | |
45 | + apiUser: api_user, | |
46 | + apiKey: api_key, | |
47 | + from: rails_message[:from].formatted.join(";"), | |
48 | + to: rails_message[:to].formatted.join(";"), | |
49 | + subject: rails_message.subject, | |
50 | + html: extract_html(rails_message), | |
51 | + plain: extract_text(rails_message), | |
52 | + fromName: rails_message['from-name'] | |
53 | + } | |
54 | + | |
55 | + [:cc, :bcc].each do |key| | |
56 | + sendcloud_message[key] = rails_message[key].formatted if rails_message[key] | |
57 | + end | |
58 | + | |
59 | + return sendcloud_message | |
60 | + end | |
61 | + | |
62 | + def transform_sendcloud_attributes_from_rails(rails_message, sendcloud_message) | |
63 | + transform_reply_to rails_message, sendcloud_message if rails_message.reply_to | |
64 | + transform_label_id rails_message, sendcloud_message | |
65 | + transform_custom_headers rails_message, sendcloud_message | |
66 | + end | |
67 | + | |
68 | + def transform_reply_to(rails_message, sendcloud_message) | |
69 | + sendcloud_message['h:Reply-To'] = rails_message[:reply_to].formatted.first | |
70 | + end | |
71 | + | |
72 | + def transform_label_id(rails_message, sendcloud_message) | |
73 | + id = label_id(rails_message) | |
74 | + sendcloud_message['labelId'] = id if id | |
75 | + end | |
76 | + | |
77 | + def extract_html(rails_message) | |
78 | + if rails_message.html_part | |
79 | + rails_message.html_part.body.decoded | |
80 | + else | |
81 | + rails_message.content_type =~ /text\/html/ ? rails_message.body.decoded : nil | |
82 | + end | |
83 | + end | |
84 | + | |
85 | + def extract_text(rails_message) | |
86 | + if rails_message.multipart? | |
87 | + rails_message.text_part ? rails_message.text_part.body.decoded : nil | |
88 | + else | |
89 | + rails_message.content_type =~ /text\/plain/ ? rails_message.body.decoded : nil | |
90 | + end | |
91 | + end | |
92 | + | |
93 | + def transform_custom_headers(rails_message, sendcloud_message) | |
94 | + rails_message.sendcloud_headers.try(:each) do |name, value| | |
95 | + sendcloud_message["h:#{name}"] = value | |
96 | + end | |
97 | + end | |
98 | + | |
99 | + def remove_empty_values(sendcloud_message) | |
100 | + sendcloud_message.delete_if { |key, value| value.nil? } | |
101 | + end | |
102 | + | |
103 | + def sendcloud_client | |
104 | + @sendcloud_client ||= Client.new(api_url) | |
105 | + end | |
106 | + | |
107 | + def label_id rails_message | |
108 | + rails_message.header.fields.find { |f| f.name == 'label-id' }.try :value | |
109 | + end | |
110 | + | |
111 | + end | |
112 | +end | |
113 | + | |
114 | +ActionMailer::Base.add_delivery_method :sendcloud, Sendcloud::Deliverer | ... | ... |
1 | +++ a/sendcloud_rails.gemspec | |
... | ... | @@ -0,0 +1,26 @@ |
1 | +$:.push File.expand_path("../lib", __FILE__) | |
2 | + | |
3 | +# Maintain your gem's version: | |
4 | +require "sendcloud/version" | |
5 | + | |
6 | +# Describe your gem and declare its dependencies: | |
7 | +Gem::Specification.new do |s| | |
8 | + s.name = "sendcloud_rails" | |
9 | + s.version = Sendcloud::VERSION | |
10 | + s.authors = ["Towon Zhou"] | |
11 | + s.email = ["towonzhou@gmail.com"] | |
12 | + s.homepage = "" | |
13 | + s.summary = "Rails Action Mailer adapter for Sendcloud" | |
14 | + s.description = "An adapter for using Sendcloud with Rails and Action Mailer" | |
15 | + s.license = 'MIT' | |
16 | + | |
17 | + s.files = Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.rdoc"] | |
18 | + s.test_files = Dir["test/**/*"] | |
19 | + | |
20 | + s.add_dependency "actionmailer", ">= 3.2.13" | |
21 | + s.add_dependency "json", ">= 1.7.7" | |
22 | + s.add_dependency "rest-client", ">= 1.6.7" | |
23 | + | |
24 | + s.add_development_dependency "rspec", '~> 2.14.1' | |
25 | + s.add_development_dependency "rails", ">= 3.2.13" | |
26 | +end | ... | ... |