pony-express 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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"