1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
|
function [retcode] = sendmail(from, to, subj, mesg, varargin)
% SENDMAIL Send Internet e-mail
% Using SENDMAIL (which needs the TCP/UDP/IP toolbox, freely available from
% http://petrydpc.ite.mh.se/tools/) it is possible to send e-mail messages
% from the Matlab prompt. This can be useful when you want to be notified
% when large jobs terminate on remote machines.
%
% Usage
% [RETCODE] = SENDMAIL(FROM, TO, SUBJ, MESG [, FILENAME]) send an e-mail with
% subject SUBJ and contents MESG to the email address in TO, with
% the From: field set to FROM.
%
% FROM, TO and SUBJ are Matlab strings. MESG can be either a
% string, or a cell array of strings.
%
% RETCODE is 0 if the message was sent succesfully, otherwise it
% has the value -1.
%
% The optional argument FILENAME is a string containing the
% filename of the file to be attached to the message. It may
% contain path information.
%
% Examples
% sendmail('me@some.where.com','me@else.where.org','Job Finished!','It took 4 days, 12 hours,6 minutes.')
%
% sendmail('me@some.where.com','me@else.where.org','Job Finished!','Finaly...', 'results.mat')
%
% Installation
% 1. Make sure the TCP/UDP/IP toolbox is somewhere in your PATH
% 2. Adjust the SMTPSERVER, SMTPSERVERPORT and CLIENTIP variables to reflect your situation.
% Author: Joris Portegies Zwart
% http://www.science.uva.nl/~portegie/
% Version 3.1
% Date: December 24, 2002
% Contributors: Simon Bridger
% Revisions :
% 3.1 Removed bug in filename extraction
% 3.0 Added attachment capabilities
% 2.1 SJB
% - Add "Content-Transfer-Encoding" to work w/outlook97/exchange server
% - Made server info optional
% - Added possibility of mesg in cell format
% 2.0 Update to use the new TCP/UDP/IP Toolbox 2.0.2
% 1.3 Added server response checking
% 1.2 Changed <CR> to <CRLF>, as in RFC821
% 1.1 Corrected minor syntax errors
% 1.0 First version
% Copyright (C) 2002 Joris Portegies Zwart
%
% This program is free software; you can redistribute it and/or
% modify it under the terms of the GNU General Public License
% as published by the Free Software Foundation; either version 2
% of the License, or (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
% GNU General Public License for more details:
%
% http://www.gnu.org/copyleft/gpl.html
ncmesg = nargchk(4, 5, nargin);
if ~isempty(ncmesg)
error(ncmesg)
end
SMTPSERVER = 'mail.server.com'; % IP adress of SMTP server
SMTPSERVERPORT = 25; % Port number, ususally 25
CLIENTIP = 'my.computerip.com'; % IP adress of client machine, usually not important
CRLF = [char(13) char(10)];
S = rand('state');
rand('state',sum(100*clock));
MIMEBREAK = char(floor(97 + 25 * rand(1, 25)));
rand('state', S);
if iscellstr(mesg) % Message is a cellarray of strings
msg_string='';
for i=1:length(mesg)
msg_string=[msg_string, mesg{i}, CRLF];
end
mesg=msg_string;
end
if (nargin==5)
fullname = varargin{1};
fsid = findstr(fullname, filesep);
if ~isempty(fsid)
filename = fullname( (fsid(end)+1):end);
else
filename = fullname;
end
disp('Encoding attachment.')
b64data = base64encode(fullname);
hasattachment = 1;
else
hasattachment = 0;
end
try
smtp_connection = pnet('tcpconnect', SMTPSERVER, SMTPSERVERPORT);
str = '';
while (isempty(str))
str=pnet(smtp_connection,'readline');
end
disp(['Connection with ' SMTPSERVER ':' num2str(SMTPSERVERPORT) ' established.']);
catch
disp('Network Connection Failed, Aborting sendmail')
retcode = -1;
return
end
Header =...
['From: ' from CRLF ...
'To: ' to CRLF ...
'Subject: ' subj CRLF ...
'MIME-Version: 1.0' CRLF ...
'Content-type: multipart/mixed; boundary="' MIMEBREAK '"' CRLF];
Message =...
['This is a multi-part message in MIME format.' CRLF CRLF ...
'--' MIMEBREAK CRLF ...
'Content-type: text/plain; charset=us-ascii' CRLF ...
'Content-transfer-encoding: 7bit' CRLF CRLF ...
mesg CRLF CRLF];
if hasattachment
Attachm =...
['--' MIMEBREAK CRLF ...
'Content-type: application/octet-stream; name="' filename '"' CRLF ...
'Content-transfer-encoding: base64' CRLF CRLF];
for n = 1:length(b64data)
Attachm = [Attachm b64data{n} CRLF];
end
else
Attachm = [];
end
Closing =[CRLF '--' MIMEBREAK '--' CRLF CRLF '.'];
try
sendcommand(smtp_connection, ['HELO ' CLIENTIP]);
sendcommand(smtp_connection, ['MAIL FROM:' from ]);
sendcommand(smtp_connection, ['RCPT TO:' to ]);
sendcommand(smtp_connection, ['DATA']);
sendcommand(smtp_connection, [Header Message Attachm Closing]);
sendcommand(smtp_connection, ['QUIT']);
catch
disp('Aborting sendmail')
pnet(smtp_connection,'close');
retcode = -1;
return
end
pnet(smtp_connection,'close');
disp('Email sent.')
retcode = 0;
return
% SENDCOMMAND %
function [str] = sendcommand(smtp_connection, command)
CRLF = [char(13) char(10)];
str = '';
% This function call should return the number of character written,
% but doesn't. The proper syntax would be
%
% numc_written = pnet(smtp_connection,'printf', '%s', [command CRLF]);
%
% but we have to use
pnet(smtp_connection,'printf', '%s', [command CRLF]);
while (isempty(str))
str = pnet(smtp_connection, 'readline');
end
% Uncomment the next line to echo all server responses
% disp(str)
resp_top = str2num(str(1));
switch resp_top
case {2, 3} % 2xx means succesful completion, 3xx means awaiting input
return
case{4} % 4xx means transient failure, could try again?
disp(['Transient failure issuing command ' command])
disp(['The server said ' str])
error('ERROR!')
case{5} % 5xx means permanent failure
disp(['Permanent failure issuing command ' command])
disp(['The server said ' str])
error('ERROR!')
otherwise % Unspecified server behaviour
disp('Unknown server response, trying to continue ...');
return
end
return
% BASE64ENCODE %
function [out] = base64encode(filename)
% This function reads a file as a bitstream, 76 groups of 6 bits at
% a time. Each group gets encoded as an 8-bit character from the
% base64 dictionary. Each line of 76 characters is stored in a cell
% of the cell array out.
BASE64 = ['ABCDEFGHIJKLMNOPQRSTUVWXYZ' ... % The Base64 dicitionary.
'abcdefghijklmnopqrstuvwxyz' ...
'0123456789+/'];
BIT2DEC = 2.^[5 4 3 2 1 0];
NBITS = 6 * 76; % Number of bits per line
fid = fopen(filename, 'r', 'b'); % Open file as big-endian
status = fseek(fid, 0, 'eof'); % Set pointer to end of file
fsize = ftell(fid); % to determine size.
frewind(fid) % Reset pointer
numlines = ceil((4 * fsize/3)/76);
out = cell(1,numlines);
for n = 1:(numlines-1) % Encoding the first numlines-1 lines is easy.
[fc, count] = fread(fid, NBITS, 'ubit1');
out{n} = BASE64(1 + BIT2DEC * reshape(fc, 6, 76));
end
% The last line needs a little more work. First, read remaining bits:
[fc, count] = fread(fid, NBITS, 'ubit1');
%Pad last part of stream so it's length is multiple of 6 bits:
fc = [fc ; zeros(6*ceil(count/6) - count, 1)];
% Encode final group of 6 bits
out{numlines} = BASE64(1 + BIT2DEC * reshape(fc, 6, length(fc)/6));
% Pad encoded stream such with '=' characters number of characters
% in encoding is integral multiple of 4
numpad = rem(fsize * 8, 24)/8;
out{numlines} = [out{end} repmat('=', 1, numpad)];
fclose(fid);
return
|