pony-express 0.2.5 → 0.5.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.
- data/README +11 -4
- data/VERSION +1 -1
- data/ext/extconf.rb +17 -5
- data/ext/mimetic.cxx +100 -10
- data/lib/pony-express.rb +7 -3
- metadata +1 -1
data/README
CHANGED
@@ -2,7 +2,7 @@ A fast and lightweight ruby mailer based on http://github.com/benprew/pony. For
|
|
2
2
|
historical perspective read http://en.wikipedia.org/wiki/Pony_Express.
|
3
3
|
|
4
4
|
INSTALL:
|
5
|
-
|
5
|
+
|
6
6
|
sudo apt-get install libmimetic-dev
|
7
7
|
sudo gem install pony-express
|
8
8
|
|
@@ -10,8 +10,9 @@ REQUIREMENT:
|
|
10
10
|
|
11
11
|
* Ruby >= 1.9.1
|
12
12
|
* rubygems >= 1.3.5
|
13
|
-
* ruby development libraries
|
14
|
-
* mimetic >= 0.9.6 development libraries
|
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)
|
15
16
|
|
16
17
|
USAGE:
|
17
18
|
|
@@ -19,12 +20,18 @@ USAGE:
|
|
19
20
|
>> args = { from: "jim@example.com", to: "ralph@example.com", subject: "test email", via: "sendmail" }
|
20
21
|
>> args[:text] = "Hello!"
|
21
22
|
>> args[:html] = "<strong>Hello!</strong>"
|
23
|
+
>> args[:attachments] = [ "/home/jim/party.png" ]
|
22
24
|
>> PonyExpress.mail(args)
|
23
25
|
|
24
26
|
|
25
27
|
TODO:
|
26
28
|
|
27
|
-
*
|
29
|
+
* Check for Memory Leaks, build a Rainbow machine and rope in some Unicorns.
|
30
|
+
|
31
|
+
DON'T ASK:
|
32
|
+
|
33
|
+
* Support for Ruby 1.8 or Rubinius or JRuby
|
34
|
+
* MIME parsing. If you need a full blown mail library have a look at the mail gem.
|
28
35
|
|
29
36
|
|
30
37
|
LICENSE:
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/ext/extconf.rb
CHANGED
@@ -7,15 +7,27 @@ $CFLAGS = "-DHAVE_INTTYPES_H"
|
|
7
7
|
Config::CONFIG['CC'] = 'g++'
|
8
8
|
Config::CONFIG['CPP'] = 'g++'
|
9
9
|
|
10
|
-
|
10
|
+
headers_mimetic = [ 'stdio.h', 'mimetic/mimetic.h' ]
|
11
|
+
headers_pcrecpp = [ 'stdio.h', 'pcre++.h' ]
|
11
12
|
|
12
|
-
|
13
|
-
if have_library('mimetic', nil, headers)
|
14
|
-
create_makefile 'mimetic'
|
15
|
-
else
|
13
|
+
if !have_library('mimetic', nil, headers_mimetic)
|
16
14
|
puts <<-ERROR
|
15
|
+
|
17
16
|
Cannot find mimetic headers or libraries.
|
18
17
|
Try sudo apt-get install libmimetic-dev on debian flavors of linux.
|
18
|
+
|
19
|
+
ERROR
|
20
|
+
exit 1
|
21
|
+
end
|
22
|
+
|
23
|
+
if !have_library('pcre++', nil, headers_pcrecpp)
|
24
|
+
puts <<-ERROR
|
25
|
+
|
26
|
+
Cannot find pcre++ headers or libraries.
|
27
|
+
Try sudo apt-get install libpcre++-dev on debian flavors of linux.
|
28
|
+
|
19
29
|
ERROR
|
20
30
|
exit 1
|
21
31
|
end
|
32
|
+
|
33
|
+
create_makefile('mimetic')
|
data/ext/mimetic.cxx
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
#include <unistd.h>
|
5
5
|
#include <sstream>
|
6
6
|
#include <exception>
|
7
|
+
#include <algorithm>
|
8
|
+
#include <pcre++.h>
|
7
9
|
#include <mimetic/mimetic.h>
|
8
10
|
|
9
11
|
#define ID_CONST_GET rb_intern("const_get")
|
@@ -15,15 +17,75 @@ static VALUE eArgumentError;
|
|
15
17
|
|
16
18
|
using namespace std;
|
17
19
|
using namespace mimetic;
|
20
|
+
using namespace pcrepp;
|
18
21
|
|
19
22
|
#define VALUEFUNC(f) ((VALUE (*)(ANYARGS)) f)
|
20
23
|
|
24
|
+
map<string, string> MimeTypes;
|
25
|
+
|
26
|
+
/* RFC References
|
27
|
+
|
28
|
+
http://www.ietf.org/rfc/rfc2822.txt Internet Message Format.
|
29
|
+
http://www.ietf.org/rfc/rfc1341.txt MIME Extensions - Multipart related.
|
30
|
+
http://www.ietf.org/rfc/rfc2392.txt Content-ID and Message-ID.
|
31
|
+
|
32
|
+
*/
|
33
|
+
|
34
|
+
// TODO: CHECK FOR MEMORY LEAKS - not sure if mimetic releases mime parts.
|
35
|
+
|
36
|
+
bool mimetic_attach_file(MimeEntity *m, char* filename, const char *mimetype) {
|
37
|
+
filebuf ifile;
|
38
|
+
ostringstream encoded;
|
39
|
+
ifile.open(filename, ios::in);
|
40
|
+
if (ifile.is_open()) {
|
41
|
+
istream is(&ifile);
|
42
|
+
Attachment *at = new Attachment(filename, ContentType(mimetype));
|
43
|
+
Base64::Encoder b64;
|
44
|
+
ostreambuf_iterator<char> oi(encoded);
|
45
|
+
istreambuf_iterator<char> ibegin(is), iend;
|
46
|
+
encode(ibegin, iend, b64, oi);
|
47
|
+
at->body().assign(encoded.str());
|
48
|
+
m->body().parts().push_back(at);
|
49
|
+
ifile.close();
|
50
|
+
return true;
|
51
|
+
}
|
52
|
+
else {
|
53
|
+
rb_raise(eRuntimeError, "Mimetic: Unable to read attachment file %s", filename);
|
54
|
+
}
|
55
|
+
return false;
|
56
|
+
}
|
57
|
+
|
58
|
+
string get_mime_type(string file) {
|
59
|
+
Pcre regex("\\.");
|
60
|
+
string extn = regex.split(file).back();
|
61
|
+
transform(extn.begin(), extn.end(), extn.begin(), ::tolower);
|
62
|
+
string mime = MimeTypes[extn];
|
63
|
+
return mime.length() > 0 ? mime : MimeTypes["bin"];
|
64
|
+
}
|
65
|
+
|
66
|
+
void rb_load_mime_types(VALUE self, VALUE filename) {
|
67
|
+
char buffer[4096];
|
68
|
+
vector<string> data;
|
69
|
+
Pcre regex("[\\r\\n\\t]+");
|
70
|
+
ifstream file(RSTRING_PTR(filename), ios::in);
|
71
|
+
if (file.is_open()) {
|
72
|
+
while (!file.eof()) {
|
73
|
+
file.getline(buffer, 4096);
|
74
|
+
data = regex.split(buffer);
|
75
|
+
for (int i = 1; i < data.size(); i++)
|
76
|
+
MimeTypes[data[i]] = data[0];
|
77
|
+
}
|
78
|
+
file.close();
|
79
|
+
}
|
80
|
+
else {
|
81
|
+
rb_raise(eRuntimeError, "Mimetic: Unable to load mime.types");
|
82
|
+
}
|
83
|
+
}
|
84
|
+
|
21
85
|
VALUE rb_mimetic_build(VALUE self, VALUE options) {
|
22
86
|
ostringstream output;
|
23
|
-
|
24
|
-
|
87
|
+
VALUE attachment;
|
25
88
|
VALUE text = rb_hash_aref(options, ID2SYM(rb_intern("text")));
|
26
|
-
VALUE html = rb_hash_aref(options, ID2SYM(rb_intern("html")));
|
27
89
|
VALUE to = rb_hash_aref(options, ID2SYM(rb_intern("to")));
|
28
90
|
VALUE from = rb_hash_aref(options, ID2SYM(rb_intern("from")));
|
29
91
|
VALUE subject = rb_hash_aref(options, ID2SYM(rb_intern("subject")));
|
@@ -33,6 +95,18 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
|
|
33
95
|
if (to == Qnil) rb_raise(eArgumentError, "Mimetic.build called without :to");
|
34
96
|
if (subject == Qnil) rb_raise(eArgumentError, "Mimetic.build called without :subject");
|
35
97
|
|
98
|
+
// optional fields
|
99
|
+
VALUE html = rb_hash_aref(options, ID2SYM(rb_intern("html")));
|
100
|
+
VALUE tcid = rb_hash_aref(options, ID2SYM(rb_intern("text_content_id")));
|
101
|
+
VALUE hcid = rb_hash_aref(options, ID2SYM(rb_intern("html_content_id")));
|
102
|
+
VALUE replyto = rb_hash_aref(options, ID2SYM(rb_intern("replyto")));
|
103
|
+
VALUE cc = rb_hash_aref(options, ID2SYM(rb_intern("cc")));
|
104
|
+
VALUE bcc = rb_hash_aref(options, ID2SYM(rb_intern("bcc")));
|
105
|
+
VALUE files = rb_hash_aref(options, ID2SYM(rb_intern("attachments")));
|
106
|
+
|
107
|
+
if (files != Qnil && TYPE(files) != T_ARRAY)
|
108
|
+
rb_raise(eArgumentError, "Mimetic.build expects :attachments to be an array");
|
109
|
+
|
36
110
|
VALUE errors = Qnil;
|
37
111
|
MimeEntity *message = NULL;
|
38
112
|
MimeEntity *html_part = NULL;
|
@@ -50,12 +124,12 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
|
|
50
124
|
message->body().parts().push_back(html_part);
|
51
125
|
text_part->header().contentType("text/plain; charset=UTF-8");
|
52
126
|
text_part->header().contentTransferEncoding("8bit");
|
53
|
-
text_part->header().
|
127
|
+
text_part->header().contentId(tcid == Qnil ? ContentId() : ContentId(RSTRING_PTR(tcid)));
|
54
128
|
text_part->header().mimeVersion(v1);
|
55
129
|
text_part->body().assign(RSTRING_PTR(text));
|
56
130
|
html_part->header().contentType("text/html; charset=UTF-8");
|
57
131
|
html_part->header().contentTransferEncoding("7bit");
|
58
|
-
html_part->header().
|
132
|
+
html_part->header().contentId(hcid == Qnil ? ContentId() : ContentId(RSTRING_PTR(hcid)));
|
59
133
|
html_part->header().mimeVersion(v1);
|
60
134
|
html_part->body().assign(RSTRING_PTR(html));
|
61
135
|
}
|
@@ -63,14 +137,30 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
|
|
63
137
|
message->body().assign(RSTRING_PTR(text));
|
64
138
|
message->header().contentType("text/plain; charset=UTF-8");
|
65
139
|
message->header().contentTransferEncoding("8bit");
|
66
|
-
message->header().messageid(message_id++);
|
67
140
|
message->header().mimeVersion(v1);
|
68
141
|
}
|
69
|
-
|
142
|
+
|
143
|
+
if (files != Qnil && RARRAY_LEN(files) > 0) {
|
144
|
+
MimeEntity *m = message;
|
145
|
+
message = new MultipartMixed();
|
146
|
+
message->header().mimeVersion(v1);
|
147
|
+
message->body().parts().push_back(m);
|
148
|
+
for (long i = 0; i < RARRAY_LEN(files); i++) {
|
149
|
+
attachment = rb_ary_entry(files, i);
|
150
|
+
if (attachment != Qnil && TYPE(attachment) == T_STRING)
|
151
|
+
mimetic_attach_file(message, RSTRING_PTR(attachment), get_mime_type(RSTRING_PTR(attachment)).c_str());
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
70
155
|
message->header().from(RSTRING_PTR(from));
|
71
156
|
message->header().to(RSTRING_PTR(to));
|
72
157
|
message->header().subject(RSTRING_PTR(subject));
|
73
|
-
|
158
|
+
message->header().messageid(1);
|
159
|
+
|
160
|
+
if (replyto != Qnil) message->header().replyto(RSTRING_PTR(replyto));
|
161
|
+
if (cc != Qnil) message->header().cc(RSTRING_PTR(cc));
|
162
|
+
if (bcc != Qnil) message->header().bcc(RSTRING_PTR(bcc));
|
163
|
+
|
74
164
|
output << *message << endl;
|
75
165
|
delete message;
|
76
166
|
return rb_str_new2(output.str().c_str());
|
@@ -86,13 +176,13 @@ VALUE rb_mimetic_build(VALUE self, VALUE options) {
|
|
86
176
|
|
87
177
|
rb_raise(eRuntimeError, "Mimetic boo boo : %s\n", RSTRING_PTR(errors));
|
88
178
|
}
|
89
|
-
|
90
|
-
|
179
|
+
|
91
180
|
extern "C" {
|
92
181
|
void Init_mimetic(void) {
|
93
182
|
eRuntimeError = CONST_GET(rb_mKernel, "RuntimeError");
|
94
183
|
eArgumentError = CONST_GET(rb_mKernel, "ArgumentError");
|
95
184
|
rb_mMimetic = rb_define_module("Mimetic");
|
96
185
|
rb_define_module_function(rb_mMimetic, "build", VALUEFUNC(rb_mimetic_build), 1);
|
186
|
+
rb_define_module_function(rb_mMimetic, "load_mime_types", VALUEFUNC(rb_load_mime_types), 1);
|
97
187
|
}
|
98
188
|
}
|
data/lib/pony-express.rb
CHANGED
@@ -6,17 +6,18 @@ module PonyExpress
|
|
6
6
|
TRANSPORTS = [ :smtp, :sendmail ]
|
7
7
|
DEFAULT_SMTP_OPTIONS = { :host => 'localhost', :port => '25', :domain => 'localhost.localdomain' }
|
8
8
|
|
9
|
+
Mimetic.load_mime_types File.dirname(__FILE__) + "/../mime.types"
|
10
|
+
|
9
11
|
def self.build options
|
10
12
|
# TODO validation.
|
11
13
|
Mimetic.build(options)
|
12
14
|
end
|
13
15
|
|
14
16
|
def self.mail options
|
15
|
-
via = options.delete(:via) ||
|
17
|
+
via = (options.delete(:via) || :smtp).to_sym
|
16
18
|
via_options = options.delete(:via_options) || {}
|
17
19
|
|
18
|
-
|
19
|
-
if TRANSPORTS.include? via.to_sym
|
20
|
+
if TRANSPORTS.include? via
|
20
21
|
case via
|
21
22
|
when :sendmail then transport_via_sendmail build(options), via_options
|
22
23
|
when :smtp then transport_via_smtp build(options), options[:from], options[:to], via_options
|
@@ -26,6 +27,8 @@ module PonyExpress
|
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
30
|
+
private
|
31
|
+
|
29
32
|
def self.sendmail_binary
|
30
33
|
sendmail = `which sendmail`.chomp
|
31
34
|
sendmail.empty? ? '/usr/sbin/sendmail' : sendmail
|
@@ -56,4 +59,5 @@ module PonyExpress
|
|
56
59
|
smtp.send_message content, from, to
|
57
60
|
smtp.finish
|
58
61
|
end
|
62
|
+
|
59
63
|
end
|