pony-express 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/README.rdoc +2 -1
  2. data/VERSION +1 -1
  3. data/ext/mimetic.cxx +79 -20
  4. data/lib/pony-express.rb +56 -14
  5. metadata +3 -6
data/README.rdoc CHANGED
@@ -21,8 +21,9 @@ historical perspective read http://en.wikipedia.org/wiki/Pony_Express.
21
21
 
22
22
  require "pony-express"
23
23
  mail = PonyExpress::Mail.new to: "burns@plant.local", from: "homer@home.local", via: "sendmail"
24
+ mail.add cc: "smithers@plant.local", bcc: "carl@plant.local", replyto: "homer+work@home.local"
24
25
  mail.add subject: "Hello Mr.Burns", text: "Can I have more donuts ?", html: "<strong>More Dooooonuuuuts!</strong>"
25
- mail.add attachments: [ "/home/homer/donuts.png" ]
26
+ mail.add attachments: [ "/home/homer/donuts.png" ], headers: [{name: "X-FooBar", value: "test"}]
26
27
  mail.dispatch
27
28
 
28
29
  Don't want to create new mail objects ? Just pass in all options to PonyExpress.mail
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.7.0
1
+ 0.8.0
data/ext/mimetic.cxx CHANGED
@@ -18,6 +18,8 @@ extern "C" {
18
18
  #define FORCE_ENCODING(str,enc) rb_enc_associate(str, rb_to_encoding(enc)); ENC_CODERANGE_CLEAR(str);
19
19
  #define TO_S(v) rb_funcall(v, rb_intern("to_s"), 0)
20
20
  #define CSTRING(v) RSTRING_PTR(TYPE(v) != T_STRING ? TO_S(v) : v)
21
+ #define RBSTRING(v) rb_str_new2(v.c_str())
22
+ #define SYM(v) ID2SYM(rb_intern(v))
21
23
 
22
24
  static VALUE rb_mMimetic;
23
25
  static VALUE rb_UTF8, rb_ASCII;
@@ -74,7 +76,7 @@ bool mimetic_attach_file(MimeEntity *m, char* filename) {
74
76
  return true;
75
77
  }
76
78
  else {
77
- rb_raise(rb_eRuntimeError, "Mimetic: Unable to read attachment file %s", filename);
79
+ rb_raise(rb_eRuntimeError, "Unable to read attachment file %s", filename);
78
80
  }
79
81
  return false;
80
82
  }
@@ -124,17 +126,17 @@ void rb_load_mime_types(VALUE self, VALUE filename) {
124
126
  file.close();
125
127
  }
126
128
  else {
127
- rb_raise(rb_eRuntimeError, "Mimetic: Unable to load mime.types");
129
+ rb_raise(rb_eRuntimeError, "Unable to load mime.types");
128
130
  }
129
131
  }
130
132
 
131
133
  VALUE rb_mimetic_build(VALUE self, VALUE options) {
132
134
  ostringstream output;
133
135
  VALUE attachment;
134
- VALUE text = rb_hash_aref(options, ID2SYM(rb_intern("text")));
135
- VALUE to = rb_hash_aref(options, ID2SYM(rb_intern("to")));
136
- VALUE from = rb_hash_aref(options, ID2SYM(rb_intern("from")));
137
- VALUE subject = rb_hash_aref(options, ID2SYM(rb_intern("subject")));
136
+ VALUE text = rb_hash_aref(options, SYM("text"));
137
+ VALUE to = rb_hash_aref(options, SYM("to"));
138
+ VALUE from = rb_hash_aref(options, SYM("from"));
139
+ VALUE subject = rb_hash_aref(options, SYM("subject"));
138
140
 
139
141
  if (text == Qnil) rb_raise(rb_eArgError, "Mimetic.build called without :text");
140
142
  if (from == Qnil) rb_raise(rb_eArgError, "Mimetic.build called without :from");
@@ -142,15 +144,15 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
142
144
  if (subject == Qnil) rb_raise(rb_eArgError, "Mimetic.build called without :subject");
143
145
 
144
146
  // optional fields
145
- VALUE mid = rb_hash_aref(options, ID2SYM(rb_intern("message_id")));
146
- VALUE html = rb_hash_aref(options, ID2SYM(rb_intern("html")));
147
- VALUE tcid = rb_hash_aref(options, ID2SYM(rb_intern("text_content_id")));
148
- VALUE hcid = rb_hash_aref(options, ID2SYM(rb_intern("html_content_id")));
149
- VALUE replyto = rb_hash_aref(options, ID2SYM(rb_intern("replyto")));
150
- VALUE cc = rb_hash_aref(options, ID2SYM(rb_intern("cc")));
151
- VALUE bcc = rb_hash_aref(options, ID2SYM(rb_intern("bcc")));
152
- VALUE files = rb_hash_aref(options, ID2SYM(rb_intern("attachments")));
153
- VALUE headers = rb_hash_aref(options, ID2SYM(rb_intern("headers")));
147
+ VALUE mid = rb_hash_aref(options, SYM("message_id"));
148
+ VALUE html = rb_hash_aref(options, SYM("html"));
149
+ VALUE tcid = rb_hash_aref(options, SYM("text_content_id"));
150
+ VALUE hcid = rb_hash_aref(options, SYM("html_content_id"));
151
+ VALUE replyto = rb_hash_aref(options, SYM("replyto"));
152
+ VALUE cc = rb_hash_aref(options, SYM("cc"));
153
+ VALUE bcc = rb_hash_aref(options, SYM("bcc"));
154
+ VALUE files = rb_hash_aref(options, SYM("attachments"));
155
+ VALUE headers = rb_hash_aref(options, SYM("headers"));
154
156
 
155
157
  if (mid != Qnil && TYPE(mid) != T_STRING)
156
158
  rb_raise(rb_eArgError, "Mimetic.build expects :message_id to be a string");
@@ -168,9 +170,9 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
168
170
  rb_raise(rb_eArgError, "Mimetic.build expects :headers to be an array");
169
171
 
170
172
  VALUE errors = Qnil;
171
- MimeEntity *message = NULL;
172
- MimeEntity *html_part = NULL;
173
- MimeEntity *text_part = NULL;
173
+ MimeEntity *message = 0;
174
+ MimeEntity *html_part = 0;
175
+ MimeEntity *text_part = 0;
174
176
  MimeVersion v1("1.0");
175
177
 
176
178
  try {
@@ -178,7 +180,7 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
178
180
 
179
181
  if (html != Qnil && text != Qnil) {
180
182
  delete message;
181
- message = new MultipartAlternative;
183
+ message = new MultipartAlternative;
182
184
  html_part = new MimeEntity;
183
185
  text_part = new MimeEntity;
184
186
  message->body().parts().push_back(text_part);
@@ -253,13 +255,70 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
253
255
  errors = rb_str_new2("Unknown Error");
254
256
  }
255
257
 
256
- rb_raise(rb_eRuntimeError, "Mimetic boo boo : %s\n", CSTRING(errors));
258
+ rb_raise(rb_eRuntimeError, "%s\n", CSTRING(errors));
259
+ }
260
+
261
+ VALUE parse_mime_parts(MimeEntity &me) {
262
+ VALUE contents = rb_ary_new();
263
+ MimeEntityList::const_iterator curr = me.body().parts().begin(), end = me.body().parts().end();
264
+ while (curr != end) {
265
+ VALUE content = rb_hash_new();
266
+ MimeEntity *part = *curr;
267
+
268
+ rb_hash_aset(content, SYM("type"), RBSTRING(part->header().contentType().str()));
269
+ if (part->header().contentType().isMultipart()) {
270
+ rb_hash_aset(content, SYM("content"), parse_mime_parts(*part));
271
+ }
272
+ else {
273
+ rb_hash_aset(content, SYM("content"), RBSTRING(part->body()));
274
+ rb_hash_aset(content, SYM("encoding"), RBSTRING(part->header().contentTransferEncoding().str()));
275
+ rb_hash_aset(content, SYM("disposition"), RBSTRING(part->header().contentDisposition().str()));
276
+ }
277
+ rb_ary_push(contents, content);
278
+ curr++;
279
+ }
280
+ return contents;
281
+ }
282
+
283
+ VALUE rb_mimetic_parse(VALUE self, VALUE data) {
284
+ if (NIL_P(data))
285
+ return Qnil;
286
+
287
+ VALUE errors = Qnil;
288
+
289
+ try {
290
+ stringstream mime;
291
+ mime << CSTRING(data);
292
+ MimeEntity me;
293
+ me.load(mime);
294
+
295
+ VALUE message = rb_hash_new();
296
+
297
+ rb_hash_aset(message, SYM("from"), RBSTRING(me.header().from().str()));
298
+ rb_hash_aset(message, SYM("to"), RBSTRING(me.header().to().str()));
299
+ rb_hash_aset(message, SYM("subject"), RBSTRING(me.header().subject()));
300
+ rb_hash_aset(message, SYM("cc"), RBSTRING(me.header().cc().str()));
301
+ rb_hash_aset(message, SYM("bcc"), RBSTRING(me.header().bcc().str()));
302
+ rb_hash_aset(message, SYM("replyto"), RBSTRING(me.header().replyto().str()));
303
+
304
+ rb_hash_aset(message, SYM("contents"), parse_mime_parts(me));
305
+ return message;
306
+ }
307
+ catch(exception &e) {
308
+ errors = rb_str_new2(e.what());
309
+ }
310
+ catch (...) {
311
+ errors = rb_str_new2("Unknown Error");
312
+ }
313
+
314
+ rb_raise(rb_eRuntimeError, "%s\n", CSTRING(errors));
257
315
  }
258
316
 
259
317
  extern "C" {
260
318
  void Init_mimetic(void) {
261
319
  rb_mMimetic = rb_define_module("Mimetic");
262
320
  rb_define_module_function(rb_mMimetic, "build", VALUEFUNC(rb_mimetic_build), 1);
321
+ rb_define_module_function(rb_mMimetic, "parse", VALUEFUNC(rb_mimetic_parse), 1);
263
322
  rb_define_module_function(rb_mMimetic, "load_mime_types", VALUEFUNC(rb_load_mime_types), 1);
264
323
  rb_UTF8 = rb_str_new2("UTF-8");
265
324
  rb_ASCII = rb_str_new2("US-ASCII");
data/lib/pony-express.rb CHANGED
@@ -3,8 +3,9 @@ begin; require 'smtp_tls'; rescue LoadError; end
3
3
  require_relative '../ext/mimetic'
4
4
 
5
5
  module PonyExpress
6
- TRANSPORTS = [ :smtp, :sendmail ]
7
- DEFAULT_SMTP_OPTIONS = { :host => 'localhost', :port => '25', :domain => 'localhost.localdomain' }
6
+ TRANSPORTS = [ :smtp, :sendmail ]
7
+ DEFAULT_SMTP_OPTIONS = { host: 'localhost', port: '25', domain: 'localhost.localdomain' }
8
+ @@sendmail_binary = '/usr/sbin/sendmail'
8
9
 
9
10
  Mimetic.load_mime_types File.dirname(__FILE__) + "/../mime.types"
10
11
 
@@ -13,8 +14,34 @@ module PonyExpress
13
14
  Mimetic.build(options)
14
15
  end
15
16
 
17
+ # NOTE: parse is very much WIP, YMMV
18
+ def parse content
19
+ Mimetic.parse(content)
20
+ end
21
+
22
+ # Build and dispatch email in one go.
23
+ #
24
+ # @example mail.
25
+ # require "pony-express"
26
+ # PonyExpress.mail to: "burns@plant.local", from: "homer@home.local", via: "sendmail",
27
+ # subject: "Hello Mr.Burns", text: "Can I have more donuts ?",
28
+ # html: "<strong>More Dooooonuuuuts!</strong>",
29
+ # attachments: [ "/home/homer/donuts.png" ],
30
+ # headers: [{name: "X-FooBar", value: "test"}]
31
+ #
32
+ # @param [String] to Email address.
33
+ # @param [String] from Email address.
34
+ # @param [String] subject Subject (will be converted to quoted printable if needed).
35
+ # @param [String] text Plain text content.
36
+ # @param [String] cc Email address (optional).
37
+ # @param [String] bcc Email address (optional).
38
+ # @param [String] replyto Email address (optional).
39
+ # @param [String] html HTML content (optional).
40
+ # @param [Array] attachments List of email attachments (optional).
41
+ # @param [Array] headers List of email headers (optional).
42
+ # @return [TrueClass or FalseClass]
16
43
  def mail options
17
- via = (options.delete(:via) || :smtp).to_sym
44
+ via = options.delete(:via) || :smtp
18
45
  via_options = options.delete(:via_options) || {}
19
46
 
20
47
  if TRANSPORTS.include? via
@@ -27,22 +54,19 @@ module PonyExpress
27
54
  end
28
55
  end
29
56
 
57
+ def sendmail_binary= binary
58
+ @@sendmail_binary = binary
59
+ end
60
+
30
61
  def sendmail_binary
31
- sendmail = `which sendmail`.chomp
32
- sendmail.empty? ? '/usr/sbin/sendmail' : sendmail
62
+ @@sendmail_binary
33
63
  end
34
64
 
35
- def transport_via_sendmail content, options={}
36
- IO.popen('-', 'w+') do |pipe|
37
- if pipe
38
- pipe.write(content)
39
- else
40
- exec(sendmail_binary, "-t")
41
- end
42
- end
65
+ def transport_via_sendmail content, options = {}
66
+ IO.popen([sendmail_binary, '-t'], 'w') {|io| io.write(content)}
43
67
  end
44
68
 
45
- def transport_via_smtp content, from, to, options={}
69
+ def transport_via_smtp content, from, to, options = {}
46
70
  o = DEFAULT_SMTP_OPTIONS.merge(options)
47
71
  smtp = Net::SMTP.new(o[:host], o[:port])
48
72
  if o[:tls]
@@ -66,19 +90,37 @@ module PonyExpress
66
90
  @options = opt
67
91
  end
68
92
 
93
+
94
+ # Add an option.
95
+ #
96
+ # @example add.
97
+ # require "pony-express"
98
+ # mail = PonyExpress::Mail.new
99
+ # mail.add to: "burns@plant.local"
69
100
  def add opt
70
101
  @options.merge! opt
71
102
  end
72
103
 
104
+ # Remove an option.
105
+ #
106
+ # @example remove.
107
+ # require "pony-express"
108
+ # mail = PonyExpress::Mail.new
109
+ # mail.add to: "burns@plant.local", cc: "smithers@plant.local"
110
+ # mail.remove :cc
73
111
  def remove opt
74
112
  keys = opt.keys
75
113
  @options.reject! {|k, v| keys.include?(k) }
76
114
  end
77
115
 
116
+ # Send the email via the selected transport.
117
+ #
78
118
  def dispatch
79
119
  mail(@options)
80
120
  end
81
121
 
122
+ # Return the encoded email content.
123
+ #
82
124
  def content
83
125
  build(@options)
84
126
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pony-express
3
3
  version: !ruby/object:Gem::Version
4
- hash: 3
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
8
- - 7
7
+ - 8
9
8
  - 0
10
- version: 0.7.0
9
+ version: 0.8.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Bharanee Rathna
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-10-15 00:00:00 +11:00
17
+ date: 2011-04-07 00:00:00 +10:00
19
18
  default_executable:
20
19
  dependencies: []
21
20
 
@@ -51,7 +50,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
51
50
  requirements:
52
51
  - - ">="
53
52
  - !ruby/object:Gem::Version
54
- hash: 3
55
53
  segments:
56
54
  - 0
57
55
  version: "0"
@@ -60,7 +58,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
60
58
  requirements:
61
59
  - - ">="
62
60
  - !ruby/object:Gem::Version
63
- hash: 3
64
61
  segments:
65
62
  - 0
66
63
  version: "0"