pony-express 0.6.1 → 0.6.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +54 -0
- data/VERSION +1 -1
- data/ext/mimetic.cxx +78 -21
- data/lib/pony-express/test.rb +19 -0
- metadata +5 -4
- data/README +0 -43
data/README.rdoc
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= Pony Express
|
2
|
+
|
3
|
+
A fast and lightweight ruby mailer based on http://github.com/benprew/pony. For a more
|
4
|
+
historical perspective read http://en.wikipedia.org/wiki/Pony_Express.
|
5
|
+
|
6
|
+
== Installation
|
7
|
+
|
8
|
+
sudo apt-get install libmimetic-dev
|
9
|
+
sudo apt-get install libpcre++-dev
|
10
|
+
sudo gem install pony-express
|
11
|
+
|
12
|
+
=== Dependencies
|
13
|
+
|
14
|
+
* Ruby >= 1.9.1
|
15
|
+
* rubygems >= 1.3.5
|
16
|
+
* ruby development libraries (debian: ruby1.9.1-dev)
|
17
|
+
* mimetic >= 0.9.6 development libraries (debian: libmimetic-dev)
|
18
|
+
* pcre++ development libraries (debian: libpcre++-dev)
|
19
|
+
|
20
|
+
== Usage
|
21
|
+
|
22
|
+
require "pony-express"
|
23
|
+
mail = PonyExpress::Mail.new to: "burns@plant.local", from: "homer@home.local", via: "sendmail"
|
24
|
+
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.dispatch
|
27
|
+
|
28
|
+
Don't want to create new mail objects ? Just pass in all options to PonyExpress.mail
|
29
|
+
|
30
|
+
PonyExpress.mail to: "burns@plant.local", from: "homer@home.local", ...
|
31
|
+
|
32
|
+
== Testing
|
33
|
+
|
34
|
+
require "pony-express"
|
35
|
+
require "pony-express/test"
|
36
|
+
mail = PonyExpress::Mail.new to: "burns@plant.local", from: "homer@home.local", via: "sendmail"
|
37
|
+
mail.add subject: "Hello Mr.Burns", text: "Can I have more donuts ?"
|
38
|
+
mail.dispatch
|
39
|
+
assert_equal 1, PonyExpress::Test.mailbox.length
|
40
|
+
|
41
|
+
== TODO
|
42
|
+
|
43
|
+
* Build a rainbow machine and rope in some unicorns.
|
44
|
+
|
45
|
+
== Won't Do
|
46
|
+
|
47
|
+
* Support for Ruby 1.8 or Rubinius or JRuby
|
48
|
+
* MIME parsing. If you need a full blown mail library have a look at the mail gem.
|
49
|
+
|
50
|
+
== License
|
51
|
+
|
52
|
+
GNU GPLv3, so its free and comes with no guarantees. If it brings down your website or burns down your house, I will
|
53
|
+
not be held responsible. Use it at your own risk. You can read all about GNU here: http://www.gnu.org and
|
54
|
+
GNU GPLv3 here: http://www.gnu.org/licenses/gpl.txt.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.6.
|
1
|
+
0.6.5
|
data/ext/mimetic.cxx
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
#include <ruby.h>
|
2
|
-
|
2
|
+
extern "C" {
|
3
|
+
#include <ruby/encoding.h>
|
4
|
+
}
|
3
5
|
#include <iostream>
|
4
6
|
#include <unistd.h>
|
5
7
|
#include <sstream>
|
@@ -10,36 +12,57 @@
|
|
10
12
|
|
11
13
|
#define ID_CONST_GET rb_intern("const_get")
|
12
14
|
#define CONST_GET(scope, constant) (rb_funcall(scope, ID_CONST_GET, 1, rb_str_new2(constant)))
|
15
|
+
#define RUBY_ENCODING(str) string(rb_enc_get(str)->name)
|
16
|
+
#define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
|
17
|
+
#define FORCE_ENCODING(str,enc) rb_enc_associate(str, rb_to_encoding(enc)); ENC_CODERANGE_CLEAR(str);
|
13
18
|
|
14
19
|
static VALUE rb_mMimetic;
|
15
20
|
static VALUE eRuntimeError;
|
16
21
|
static VALUE eArgumentError;
|
22
|
+
static VALUE rb_UTF8, rb_ASCII;
|
17
23
|
|
18
24
|
using namespace std;
|
19
25
|
using namespace mimetic;
|
20
26
|
using namespace pcrepp;
|
21
27
|
|
22
|
-
#define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
|
23
|
-
|
24
28
|
map<string, string> MimeTypes;
|
25
29
|
|
26
30
|
/* RFC References
|
27
31
|
|
28
32
|
http://www.ietf.org/rfc/rfc2822.txt Internet Message Format.
|
29
|
-
http://www.ietf.org/rfc/
|
33
|
+
http://www.ietf.org/rfc/rfc2045.txt MIME Extensions - Multipart related (Part One).
|
34
|
+
http://www.ietf.org/rfc/rfc2046.txt MIME Extensions - Multipart related (Part Deux).
|
30
35
|
http://www.ietf.org/rfc/rfc2392.txt Content-ID and Message-ID.
|
31
36
|
|
32
37
|
*/
|
33
38
|
|
34
|
-
// TODO
|
39
|
+
// TODO
|
40
|
+
// angle brackets enclosing content and message ids should be part of libmimetic.
|
41
|
+
string content_id() {
|
42
|
+
string cid = ContentId().str();
|
43
|
+
return cid[0] == '<' ? cid : "<" + cid + ">";
|
44
|
+
}
|
45
|
+
|
46
|
+
string message_id(int n) {
|
47
|
+
string mid = MessageId(n).str();
|
48
|
+
return mid[0] == '<' ? mid : "<" + mid + ">";
|
49
|
+
}
|
50
|
+
|
51
|
+
string file_mime_type(string file) {
|
52
|
+
Pcre regex("\\.");
|
53
|
+
string extn = regex.split(file).back();
|
54
|
+
transform(extn.begin(), extn.end(), extn.begin(), ::tolower);
|
55
|
+
string mime = MimeTypes[extn];
|
56
|
+
return mime.length() > 0 ? mime : "application/octet-stream";
|
57
|
+
}
|
35
58
|
|
36
|
-
bool mimetic_attach_file(MimeEntity *m, char* filename
|
59
|
+
bool mimetic_attach_file(MimeEntity *m, char* filename) {
|
37
60
|
filebuf ifile;
|
38
61
|
ostringstream encoded;
|
39
62
|
ifile.open(filename, ios::in);
|
40
63
|
if (ifile.is_open()) {
|
41
64
|
istream is(&ifile);
|
42
|
-
Attachment *at = new Attachment(filename, ContentType(
|
65
|
+
Attachment *at = new Attachment(filename, ContentType(file_mime_type(filename)));
|
43
66
|
Base64::Encoder b64;
|
44
67
|
ostreambuf_iterator<char> oi(encoded);
|
45
68
|
istreambuf_iterator<char> ibegin(is), iend;
|
@@ -55,14 +78,36 @@ bool mimetic_attach_file(MimeEntity *m, char* filename, const char *mimetype) {
|
|
55
78
|
return false;
|
56
79
|
}
|
57
80
|
|
58
|
-
string
|
59
|
-
Pcre
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
81
|
+
string safe_rfc2047(string v) {
|
82
|
+
Pcre re1("\\?");
|
83
|
+
Pcre re2("_");
|
84
|
+
Pcre re3(" ");
|
85
|
+
v = re1.replace(v, "=3F");
|
86
|
+
v = re2.replace(v, "=5F");
|
87
|
+
v = re3.replace(v, "_");
|
88
|
+
return v;
|
64
89
|
}
|
65
90
|
|
91
|
+
string quoted_printable(VALUE str) {
|
92
|
+
VALUE ascii = rb_str_new2(RSTRING_PTR(str));
|
93
|
+
FORCE_ENCODING(ascii, rb_ASCII);
|
94
|
+
if (rb_str_cmp(ascii, str) != 0) {
|
95
|
+
string raw = RSTRING_PTR(str);
|
96
|
+
QP::Encoder qp;
|
97
|
+
istringstream is(raw);
|
98
|
+
ostringstream encoded;
|
99
|
+
istreambuf_iterator<char> ibeg(is), iend;
|
100
|
+
ostreambuf_iterator<char> oi(encoded);
|
101
|
+
encode(ibeg, iend, qp, oi);
|
102
|
+
return "=?" + RUBY_ENCODING(str) + "?Q?" + safe_rfc2047(encoded.str()) + "?=";
|
103
|
+
}
|
104
|
+
else {
|
105
|
+
return string(RSTRING_PTR(str));
|
106
|
+
}
|
107
|
+
}
|
108
|
+
|
109
|
+
// Exposed API
|
110
|
+
|
66
111
|
void rb_load_mime_types(VALUE self, VALUE filename) {
|
67
112
|
char buffer[4096];
|
68
113
|
vector<string> data;
|
@@ -96,6 +141,7 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
|
|
96
141
|
if (subject == Qnil) rb_raise(eArgumentError, "Mimetic.build called without :subject");
|
97
142
|
|
98
143
|
// optional fields
|
144
|
+
VALUE mid = rb_hash_aref(options, ID2SYM(rb_intern("message_id")));
|
99
145
|
VALUE html = rb_hash_aref(options, ID2SYM(rb_intern("html")));
|
100
146
|
VALUE tcid = rb_hash_aref(options, ID2SYM(rb_intern("text_content_id")));
|
101
147
|
VALUE hcid = rb_hash_aref(options, ID2SYM(rb_intern("html_content_id")));
|
@@ -104,6 +150,15 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
|
|
104
150
|
VALUE bcc = rb_hash_aref(options, ID2SYM(rb_intern("bcc")));
|
105
151
|
VALUE files = rb_hash_aref(options, ID2SYM(rb_intern("attachments")));
|
106
152
|
|
153
|
+
if (mid != Qnil && TYPE(mid) != T_STRING)
|
154
|
+
rb_raise(eArgumentError, "Mimetic.build expects :message_id to be a string");
|
155
|
+
|
156
|
+
if (tcid != Qnil && TYPE(tcid) != T_STRING)
|
157
|
+
rb_raise(eArgumentError, "Mimetic.build expects :text_content_id to be a string");
|
158
|
+
|
159
|
+
if (hcid != Qnil && TYPE(hcid) != T_STRING)
|
160
|
+
rb_raise(eArgumentError, "Mimetic.build expects :html_content_id to be a string");
|
161
|
+
|
107
162
|
if (files != Qnil && TYPE(files) != T_ARRAY)
|
108
163
|
rb_raise(eArgumentError, "Mimetic.build expects :attachments to be an array");
|
109
164
|
|
@@ -122,20 +177,20 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
|
|
122
177
|
text_part = new MimeEntity;
|
123
178
|
message->body().parts().push_back(text_part);
|
124
179
|
message->body().parts().push_back(html_part);
|
125
|
-
text_part->header().contentType("text/plain; charset=
|
180
|
+
text_part->header().contentType("text/plain; charset=" + RUBY_ENCODING(text));
|
126
181
|
text_part->header().contentTransferEncoding("8bit");
|
127
|
-
text_part->header().contentId(tcid == Qnil ?
|
182
|
+
text_part->header().contentId(tcid == Qnil ? content_id() + ">" : ContentId(RSTRING_PTR(tcid)));
|
128
183
|
text_part->header().mimeVersion(v1);
|
129
184
|
text_part->body().assign(RSTRING_PTR(text));
|
130
|
-
html_part->header().contentType("text/html; charset=
|
185
|
+
html_part->header().contentType("text/html; charset=" + RUBY_ENCODING(html));
|
131
186
|
html_part->header().contentTransferEncoding("7bit");
|
132
|
-
html_part->header().contentId(hcid == Qnil ?
|
187
|
+
html_part->header().contentId(hcid == Qnil ? content_id() + ">" : ContentId(RSTRING_PTR(hcid)));
|
133
188
|
html_part->header().mimeVersion(v1);
|
134
189
|
html_part->body().assign(RSTRING_PTR(html));
|
135
190
|
}
|
136
191
|
else {
|
137
192
|
message->body().assign(RSTRING_PTR(text));
|
138
|
-
message->header().contentType("text/plain; charset=
|
193
|
+
message->header().contentType("text/plain; charset=" + RUBY_ENCODING(text));
|
139
194
|
message->header().contentTransferEncoding("8bit");
|
140
195
|
message->header().mimeVersion(v1);
|
141
196
|
}
|
@@ -148,14 +203,14 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
|
|
148
203
|
for (long i = 0; i < RARRAY_LEN(files); i++) {
|
149
204
|
attachment = rb_ary_entry(files, i);
|
150
205
|
if (attachment != Qnil && TYPE(attachment) == T_STRING)
|
151
|
-
mimetic_attach_file(message, RSTRING_PTR(attachment)
|
206
|
+
mimetic_attach_file(message, RSTRING_PTR(attachment));
|
152
207
|
}
|
153
208
|
}
|
154
209
|
|
155
210
|
message->header().from(RSTRING_PTR(from));
|
156
211
|
message->header().to(RSTRING_PTR(to));
|
157
|
-
message->header().subject(
|
158
|
-
message->header().messageid(1);
|
212
|
+
message->header().subject(quoted_printable(subject));
|
213
|
+
message->header().messageid(mid != Qnil ? RSTRING_PTR(mid) : message_id(1));
|
159
214
|
|
160
215
|
if (replyto != Qnil) message->header().replyto(RSTRING_PTR(replyto));
|
161
216
|
if (cc != Qnil) message->header().cc(RSTRING_PTR(cc));
|
@@ -184,5 +239,7 @@ extern "C" {
|
|
184
239
|
rb_mMimetic = rb_define_module("Mimetic");
|
185
240
|
rb_define_module_function(rb_mMimetic, "build", VALUEFUNC(rb_mimetic_build), 1);
|
186
241
|
rb_define_module_function(rb_mMimetic, "load_mime_types", VALUEFUNC(rb_load_mime_types), 1);
|
242
|
+
rb_UTF8 = rb_str_new2("UTF-8");
|
243
|
+
rb_ASCII = rb_str_new2("US-ASCII");
|
187
244
|
}
|
188
245
|
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module PonyExpress
|
2
|
+
module Test
|
3
|
+
def mailbox
|
4
|
+
PonyExpress::Test.mailbox
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.mailbox
|
8
|
+
@@mailbox ||= []
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.transport_via_sendmail content, *rest
|
13
|
+
PonyExpress::Test.mailbox << content
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.transport_via_smtp content, *rest
|
17
|
+
PonyExpress::Test.mailbox << content
|
18
|
+
end
|
19
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pony-express
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.6.
|
4
|
+
version: 0.6.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bharanee Rathna
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-06-
|
12
|
+
date: 2010-06-08 00:00:00 +10:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -21,14 +21,15 @@ extensions:
|
|
21
21
|
- ext/extconf.rb
|
22
22
|
extra_rdoc_files:
|
23
23
|
- LICENSE
|
24
|
-
- README
|
24
|
+
- README.rdoc
|
25
25
|
files:
|
26
26
|
- LICENSE
|
27
|
-
- README
|
28
27
|
- VERSION
|
29
28
|
- ext/mimetic.cxx
|
30
29
|
- lib/pony-express.rb
|
30
|
+
- lib/pony-express/test.rb
|
31
31
|
- mime.types
|
32
|
+
- README.rdoc
|
32
33
|
has_rdoc: true
|
33
34
|
homepage: http://github.com/deepfryed/pony-express
|
34
35
|
licenses: []
|
data/README
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
A fast and lightweight ruby mailer based on http://github.com/benprew/pony. For a more
|
2
|
-
historical perspective read http://en.wikipedia.org/wiki/Pony_Express.
|
3
|
-
|
4
|
-
INSTALL:
|
5
|
-
|
6
|
-
sudo apt-get install libmimetic-dev
|
7
|
-
sudo gem install pony-express
|
8
|
-
|
9
|
-
REQUIREMENT:
|
10
|
-
|
11
|
-
* Ruby >= 1.9.1
|
12
|
-
* rubygems >= 1.3.5
|
13
|
-
* ruby development libraries (debian: ruby1.9.1-dev)
|
14
|
-
* mimetic >= 0.9.6 development libraries (debian: libmimetic-dev)
|
15
|
-
* pcre++ development libraries (debian: libpcre++-dev)
|
16
|
-
|
17
|
-
USAGE:
|
18
|
-
|
19
|
-
>> require "pony-express"
|
20
|
-
>> mail = PonyExpress::Mail.new to: "burns@plant.local", from: "homer@home.local", via: "sendmail"
|
21
|
-
>> mail.add subject: "Hello Mr.Burns", text: "Can I have more donuts", html: "<strong>More Dooooonuuuuts!</strong>"
|
22
|
-
>> mail.add attachments: [ "/home/homer/donuts.png" ]
|
23
|
-
>> mail.dispatch
|
24
|
-
|
25
|
-
Don't want to create new mail objects ? Just pass in all options to PonyExpress.mail
|
26
|
-
|
27
|
-
>> PonyExpress.mail to: "burns@plant.local", from: "homer@home.local", ...
|
28
|
-
|
29
|
-
TODO:
|
30
|
-
|
31
|
-
* Check for Memory Leaks, build a Rainbow machine and rope in some Unicorns.
|
32
|
-
|
33
|
-
DON'T ASK:
|
34
|
-
|
35
|
-
* Support for Ruby 1.8 or Rubinius or JRuby
|
36
|
-
* MIME parsing. If you need a full blown mail library have a look at the mail gem.
|
37
|
-
|
38
|
-
|
39
|
-
LICENSE:
|
40
|
-
|
41
|
-
GNU GPLv3, so its free and comes with no guarantees. If it brings down your website or burns down your house, I will
|
42
|
-
not be held responsible. Use it at your own risk. You can read all about GNU here: http://www.gnu.org and
|
43
|
-
GNU GPLv3 here: http://www.gnu.org/licenses/gpl.txt.
|