001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.net.smtp; 019 020import java.io.IOException; 021import java.io.Writer; 022import java.net.InetAddress; 023 024import org.apache.commons.net.io.DotTerminatedMessageWriter; 025 026/*** 027 * SMTPClient encapsulates all the functionality necessary to send files 028 * through an SMTP server. This class takes care of all 029 * low level details of interacting with an SMTP server and provides 030 * a convenient higher level interface. As with all classes derived 031 * from {@link org.apache.commons.net.SocketClient}, 032 * you must first connect to the server with 033 * {@link org.apache.commons.net.SocketClient#connect connect } 034 * before doing anything, and finally 035 * {@link org.apache.commons.net.SocketClient#disconnect disconnect } 036 * after you're completely finished interacting with the server. 037 * Then you need to check the SMTP reply code to see if the connection 038 * was successful. For example: 039 * <pre> 040 * try { 041 * int reply; 042 * client.connect("mail.foobar.com"); 043 * System.out.print(client.getReplyString()); 044 * 045 * // After connection attempt, you should check the reply code to verify 046 * // success. 047 * reply = client.getReplyCode(); 048 * 049 * if(!SMTPReply.isPositiveCompletion(reply)) { 050 * client.disconnect(); 051 * System.err.println("SMTP server refused connection."); 052 * System.exit(1); 053 * } 054 * 055 * // Do useful stuff here. 056 * ... 057 * } catch(IOException e) { 058 * if(client.isConnected()) { 059 * try { 060 * client.disconnect(); 061 * } catch(IOException f) { 062 * // do nothing 063 * } 064 * } 065 * System.err.println("Could not connect to server."); 066 * e.printStackTrace(); 067 * System.exit(1); 068 * } 069 * </pre> 070 * <p> 071 * Immediately after connecting is the only real time you need to check the 072 * reply code (because connect is of type void). The convention for all the 073 * SMTP command methods in SMTPClient is such that they either return a 074 * boolean value or some other value. 075 * The boolean methods return true on a successful completion reply from 076 * the SMTP server and false on a reply resulting in an error condition or 077 * failure. The methods returning a value other than boolean return a value 078 * containing the higher level data produced by the SMTP command, or null if a 079 * reply resulted in an error condition or failure. If you want to access 080 * the exact SMTP reply code causing a success or failure, you must call 081 * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode } after 082 * a success or failure. 083 * <p> 084 * You should keep in mind that the SMTP server may choose to prematurely 085 * close a connection for various reasons. The SMTPClient class will detect a 086 * premature SMTP server connection closing when it receives a 087 * {@link org.apache.commons.net.smtp.SMTPReply#SERVICE_NOT_AVAILABLE SMTPReply.SERVICE_NOT_AVAILABLE } 088 * response to a command. 089 * When that occurs, the method encountering that reply will throw 090 * an {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} 091 * . 092 * <code>SMTPConectionClosedException</code> 093 * is a subclass of <code> IOException </code> and therefore need not be 094 * caught separately, but if you are going to catch it separately, its 095 * catch block must appear before the more general <code> IOException </code> 096 * catch block. When you encounter an 097 * {@link org.apache.commons.net.smtp.SMTPConnectionClosedException} 098 * , you must disconnect the connection with 099 * {@link #disconnect disconnect() } to properly clean up the 100 * system resources used by SMTPClient. Before disconnecting, you may check 101 * the last reply code and text with 102 * {@link org.apache.commons.net.smtp.SMTP#getReplyCode getReplyCode }, 103 * {@link org.apache.commons.net.smtp.SMTP#getReplyString getReplyString }, 104 * and 105 * {@link org.apache.commons.net.smtp.SMTP#getReplyStrings getReplyStrings}. 106 * <p> 107 * Rather than list it separately for each method, we mention here that 108 * every method communicating with the server and throwing an IOException 109 * can also throw a 110 * {@link org.apache.commons.net.MalformedServerReplyException} 111 * , which is a subclass 112 * of IOException. A MalformedServerReplyException will be thrown when 113 * the reply received from the server deviates enough from the protocol 114 * specification that it cannot be interpreted in a useful manner despite 115 * attempts to be as lenient as possible. 116 * 117 * @see SMTP 118 * @see SimpleSMTPHeader 119 * @see RelayPath 120 * @see SMTPConnectionClosedException 121 * @see org.apache.commons.net.MalformedServerReplyException 122 ***/ 123 124public class SMTPClient extends SMTP 125{ 126 127 /** 128 * Default SMTPClient constructor. Creates a new SMTPClient instance. 129 */ 130 public SMTPClient() { } 131 132 /** 133 * Overloaded constructor that takes an encoding specification 134 * @param encoding The encoding to use 135 * @since 2.0 136 */ 137 public SMTPClient(String encoding) { 138 super(encoding); 139 } 140 141 142 /*** 143 * At least one SMTPClient method ({@link #sendMessageData sendMessageData }) 144 * does not complete the entire sequence of SMTP commands to complete a 145 * transaction. These types of commands require some action by the 146 * programmer after the reception of a positive intermediate command. 147 * After the programmer's code completes its actions, it must call this 148 * method to receive the completion reply from the server and verify the 149 * success of the entire transaction. 150 * <p> 151 * For example, 152 * <pre> 153 * writer = client.sendMessageData(); 154 * if(writer == null) // failure 155 * return false; 156 * header = 157 * new SimpleSMTPHeader("foobar@foo.com", "foo@foobar.com", "Re: Foo"); 158 * writer.write(header.toString()); 159 * writer.write("This is just a test"); 160 * writer.close(); 161 * if(!client.completePendingCommand()) // failure 162 * return false; 163 * </pre> 164 * <p> 165 * @return True if successfully completed, false if not. 166 * @exception SMTPConnectionClosedException 167 * If the SMTP server prematurely closes the connection as a result 168 * of the client being idle or some other reason causing the server 169 * to send SMTP reply code 421. This exception may be caught either 170 * as an IOException or independently as itself. 171 * @exception IOException If an I/O error occurs while either sending a 172 * command to the server or receiving a reply from the server. 173 ***/ 174 public boolean completePendingCommand() throws IOException 175 { 176 return SMTPReply.isPositiveCompletion(getReply()); 177 } 178 179 180 /*** 181 * Login to the SMTP server by sending the HELO command with the 182 * given hostname as an argument. Before performing any mail commands, 183 * you must first login. 184 * <p> 185 * @param hostname The hostname with which to greet the SMTP server. 186 * @return True if successfully completed, false if not. 187 * @exception SMTPConnectionClosedException 188 * If the SMTP server prematurely closes the connection as a result 189 * of the client being idle or some other reason causing the server 190 * to send SMTP reply code 421. This exception may be caught either 191 * as an IOException or independently as itself. 192 * @exception IOException If an I/O error occurs while either sending a 193 * command to the server or receiving a reply from the server. 194 ***/ 195 public boolean login(String hostname) throws IOException 196 { 197 return SMTPReply.isPositiveCompletion(helo(hostname)); 198 } 199 200 201 /*** 202 * Login to the SMTP server by sending the HELO command with the 203 * client hostname as an argument. Before performing any mail commands, 204 * you must first login. 205 * <p> 206 * @return True if successfully completed, false if not. 207 * @exception SMTPConnectionClosedException 208 * If the SMTP server prematurely closes the connection as a result 209 * of the client being idle or some other reason causing the server 210 * to send SMTP reply code 421. This exception may be caught either 211 * as an IOException or independently as itself. 212 * @exception IOException If an I/O error occurs while either sending a 213 * command to the server or receiving a reply from the server. 214 ***/ 215 public boolean login() throws IOException 216 { 217 String name; 218 InetAddress host; 219 220 host = getLocalAddress(); 221 name = host.getHostName(); 222 223 if (name == null) { 224 return false; 225 } 226 227 return SMTPReply.isPositiveCompletion(helo(name)); 228 } 229 230 231 /*** 232 * Set the sender of a message using the SMTP MAIL command, specifying 233 * a reverse relay path. The sender must be set first before any 234 * recipients may be specified, otherwise the mail server will reject 235 * your commands. 236 * <p> 237 * @param path The reverse relay path pointing back to the sender. 238 * @return True if successfully completed, false if not. 239 * @exception SMTPConnectionClosedException 240 * If the SMTP server prematurely closes the connection as a result 241 * of the client being idle or some other reason causing the server 242 * to send SMTP reply code 421. This exception may be caught either 243 * as an IOException or independently as itself. 244 * @exception IOException If an I/O error occurs while either sending a 245 * command to the server or receiving a reply from the server. 246 ***/ 247 public boolean setSender(RelayPath path) throws IOException 248 { 249 return SMTPReply.isPositiveCompletion(mail(path.toString())); 250 } 251 252 253 /*** 254 * Set the sender of a message using the SMTP MAIL command, specifying 255 * the sender's email address. The sender must be set first before any 256 * recipients may be specified, otherwise the mail server will reject 257 * your commands. 258 * <p> 259 * @param address The sender's email address. 260 * @return True if successfully completed, false if not. 261 * @exception SMTPConnectionClosedException 262 * If the SMTP server prematurely closes the connection as a result 263 * of the client being idle or some other reason causing the server 264 * to send SMTP reply code 421. This exception may be caught either 265 * as an IOException or independently as itself. 266 * @exception IOException If an I/O error occurs while either sending a 267 * command to the server or receiving a reply from the server. 268 ***/ 269 public boolean setSender(String address) throws IOException 270 { 271 return SMTPReply.isPositiveCompletion(mail("<" + address + ">")); 272 } 273 274 275 /*** 276 * Add a recipient for a message using the SMTP RCPT command, specifying 277 * a forward relay path. The sender must be set first before any 278 * recipients may be specified, otherwise the mail server will reject 279 * your commands. 280 * <p> 281 * @param path The forward relay path pointing to the recipient. 282 * @return True if successfully completed, false if not. 283 * @exception SMTPConnectionClosedException 284 * If the SMTP server prematurely closes the connection as a result 285 * of the client being idle or some other reason causing the server 286 * to send SMTP reply code 421. This exception may be caught either 287 * as an IOException or independently as itself. 288 * @exception IOException If an I/O error occurs while either sending a 289 * command to the server or receiving a reply from the server. 290 ***/ 291 public boolean addRecipient(RelayPath path) throws IOException 292 { 293 return SMTPReply.isPositiveCompletion(rcpt(path.toString())); 294 } 295 296 297 /*** 298 * Add a recipient for a message using the SMTP RCPT command, the 299 * recipient's email address. The sender must be set first before any 300 * recipients may be specified, otherwise the mail server will reject 301 * your commands. 302 * <p> 303 * @param address The recipient's email address. 304 * @return True if successfully completed, false if not. 305 * @exception SMTPConnectionClosedException 306 * If the SMTP server prematurely closes the connection as a result 307 * of the client being idle or some other reason causing the server 308 * to send SMTP reply code 421. This exception may be caught either 309 * as an IOException or independently as itself. 310 * @exception IOException If an I/O error occurs while either sending a 311 * command to the server or receiving a reply from the server. 312 ***/ 313 public boolean addRecipient(String address) throws IOException 314 { 315 return SMTPReply.isPositiveCompletion(rcpt("<" + address + ">")); 316 } 317 318 319 320 /*** 321 * Send the SMTP DATA command in preparation to send an email message. 322 * This method returns a DotTerminatedMessageWriter instance to which 323 * the message can be written. Null is returned if the DATA command 324 * fails. 325 * <p> 326 * You must not issue any commands to the SMTP server (i.e., call any 327 * (other methods) until you finish writing to the returned Writer 328 * instance and close it. The SMTP protocol uses the same stream for 329 * issuing commands as it does for returning results. Therefore the 330 * returned Writer actually writes directly to the SMTP connection. 331 * After you close the writer, you can execute new commands. If you 332 * do not follow these requirements your program will not work properly. 333 * <p> 334 * You can use the provided 335 * {@link org.apache.commons.net.smtp.SimpleSMTPHeader} 336 * class to construct a bare minimum header. 337 * To construct more complicated headers you should 338 * refer to RFC 5322. When the Java Mail API is finalized, you will be 339 * able to use it to compose fully compliant Internet text messages. 340 * The DotTerminatedMessageWriter takes care of doubling line-leading 341 * dots and ending the message with a single dot upon closing, so all 342 * you have to worry about is writing the header and the message. 343 * <p> 344 * Upon closing the returned Writer, you need to call 345 * {@link #completePendingCommand completePendingCommand() } 346 * to finalize the transaction and verify its success or failure from 347 * the server reply. 348 * <p> 349 * @return A DotTerminatedMessageWriter to which the message (including 350 * header) can be written. Returns null if the command fails. 351 * @exception SMTPConnectionClosedException 352 * If the SMTP server prematurely closes the connection as a result 353 * of the client being idle or some other reason causing the server 354 * to send SMTP reply code 421. This exception may be caught either 355 * as an IOException or independently as itself. 356 * @exception IOException If an I/O error occurs while either sending a 357 * command to the server or receiving a reply from the server. 358 * @see #sendShortMessageData(String) 359 ***/ 360 public Writer sendMessageData() throws IOException 361 { 362 if (!SMTPReply.isPositiveIntermediate(data())) { 363 return null; 364 } 365 366 return new DotTerminatedMessageWriter(_writer); 367 } 368 369 370 /*** 371 * A convenience method for sending short messages. This method fetches 372 * the Writer returned by {@link #sendMessageData sendMessageData() } 373 * and writes the specified String to it. After writing the message, 374 * this method calls {@link #completePendingCommand completePendingCommand() } 375 * to finalize the transaction and returns 376 * its success or failure. 377 * <p> 378 * @param message The short email message to send. 379 * This must include the headers and the body, but not the trailing "." 380 * @return True if successfully completed, false if not. 381 * @exception SMTPConnectionClosedException 382 * If the SMTP server prematurely closes the connection as a result 383 * of the client being idle or some other reason causing the server 384 * to send SMTP reply code 421. This exception may be caught either 385 * as an IOException or independently as itself. 386 * @exception IOException If an I/O error occurs while either sending a 387 * command to the server or receiving a reply from the server. 388 ***/ 389 public boolean sendShortMessageData(String message) throws IOException 390 { 391 Writer writer; 392 393 writer = sendMessageData(); 394 395 if (writer == null) { 396 return false; 397 } 398 399 writer.write(message); 400 writer.close(); 401 402 return completePendingCommand(); 403 } 404 405 406 /*** 407 * A convenience method for a sending short email without having to 408 * explicitly set the sender and recipient(s). This method 409 * sets the sender and recipient using 410 * {@link #setSender setSender } and 411 * {@link #addRecipient addRecipient }, and then sends the 412 * message using {@link #sendShortMessageData sendShortMessageData }. 413 * <p> 414 * @param sender The email address of the sender. 415 * @param recipient The email address of the recipient. 416 * @param message The short email message to send. 417 * This must include the headers and the body, but not the trailing "." 418 * @return True if successfully completed, false if not. 419 * @exception SMTPConnectionClosedException 420 * If the SMTP server prematurely closes the connection as a result 421 * of the client being idle or some other reason causing the server 422 * to send SMTP reply code 421. This exception may be caught either 423 * as an IOException or independently as itself. 424 * @exception IOException If an I/O error occurs while either sending a 425 * command to the server or receiving a reply from the server. 426 ***/ 427 public boolean sendSimpleMessage(String sender, String recipient, 428 String message) 429 throws IOException 430 { 431 if (!setSender(sender)) { 432 return false; 433 } 434 435 if (!addRecipient(recipient)) { 436 return false; 437 } 438 439 return sendShortMessageData(message); 440 } 441 442 443 444 /*** 445 * A convenience method for a sending short email without having to 446 * explicitly set the sender and recipient(s). This method 447 * sets the sender and recipients using 448 * {@link #setSender(String) setSender} and 449 * {@link #addRecipient(String) addRecipient}, and then sends the 450 * message using {@link #sendShortMessageData(String) sendShortMessageData}. 451 * <p> 452 * Note that the method ignores failures when calling 453 * {@link #addRecipient(String) addRecipient} so long as 454 * at least one call succeeds. If no recipients can be successfully 455 * added then the method will fail (and does not attempt to 456 * send the message) 457 * <p> 458 * @param sender The email address of the sender. 459 * @param recipients An array of recipient email addresses. 460 * @param message The short email message to send. 461 * This must include the headers and the body, but not the trailing "." 462 * @return True if successfully completed, false if not. 463 * @exception SMTPConnectionClosedException 464 * If the SMTP server prematurely closes the connection as a result 465 * of the client being idle or some other reason causing the server 466 * to send SMTP reply code 421. This exception may be caught either 467 * as an IOException or independently as itself. 468 * @exception IOException If an I/O error occurs while either sending a 469 * command to the server or receiving a reply from the server. 470 ***/ 471 public boolean sendSimpleMessage(String sender, String[] recipients, 472 String message) 473 throws IOException 474 { 475 boolean oneSuccess = false; 476 int count; 477 478 if (!setSender(sender)) { 479 return false; 480 } 481 482 for (count = 0; count < recipients.length; count++) 483 { 484 if (addRecipient(recipients[count])) { 485 oneSuccess = true; 486 } 487 } 488 489 if (!oneSuccess) { 490 return false; 491 } 492 493 return sendShortMessageData(message); 494 } 495 496 497 /*** 498 * Logout of the SMTP server by sending the QUIT command. 499 * <p> 500 * @return True if successfully completed, false if not. 501 * @exception SMTPConnectionClosedException 502 * If the SMTP server prematurely closes the connection as a result 503 * of the client being idle or some other reason causing the server 504 * to send SMTP reply code 421. This exception may be caught either 505 * as an IOException or independently as itself. 506 * @exception IOException If an I/O error occurs while either sending a 507 * command to the server or receiving a reply from the server. 508 ***/ 509 public boolean logout() throws IOException 510 { 511 return SMTPReply.isPositiveCompletion(quit()); 512 } 513 514 515 516 /*** 517 * Aborts the current mail transaction, resetting all server stored 518 * sender, recipient, and mail data, cleaing all buffers and tables. 519 * <p> 520 * @return True if successfully completed, false if not. 521 * @exception SMTPConnectionClosedException 522 * If the SMTP server prematurely closes the connection as a result 523 * of the client being idle or some other reason causing the server 524 * to send SMTP reply code 421. This exception may be caught either 525 * as an IOException or independently as itself. 526 * @exception IOException If an I/O error occurs while either sending a 527 * command to the server or receiving a reply from the server. 528 ***/ 529 public boolean reset() throws IOException 530 { 531 return SMTPReply.isPositiveCompletion(rset()); 532 } 533 534 535 /*** 536 * Verify that a username or email address is valid, i.e., that mail 537 * can be delivered to that mailbox on the server. 538 * <p> 539 * @param username The username or email address to validate. 540 * @return True if the username is valid, false if not. 541 * @exception SMTPConnectionClosedException 542 * If the SMTP server prematurely closes the connection as a result 543 * of the client being idle or some other reason causing the server 544 * to send SMTP reply code 421. This exception may be caught either 545 * as an IOException or independently as itself. 546 * @exception IOException If an I/O error occurs while either sending a 547 * command to the server or receiving a reply from the server. 548 ***/ 549 public boolean verify(String username) throws IOException 550 { 551 int result; 552 553 result = vrfy(username); 554 555 return (result == SMTPReply.ACTION_OK || 556 result == SMTPReply.USER_NOT_LOCAL_WILL_FORWARD); 557 } 558 559 560 /*** 561 * Fetches the system help information from the server and returns the 562 * full string. 563 * <p> 564 * @return The system help string obtained from the server. null if the 565 * information could not be obtained. 566 * @exception SMTPConnectionClosedException 567 * If the SMTP server prematurely closes the connection as a result 568 * of the client being idle or some other reason causing the server 569 * to send SMTP reply code 421. This exception may be caught either 570 * as an IOException or independently as itself. 571 * @exception IOException If an I/O error occurs while either sending a 572 * command to the server or receiving a reply from the server. 573 ***/ 574 public String listHelp() throws IOException 575 { 576 if (SMTPReply.isPositiveCompletion(help())) { 577 return getReplyString(); 578 } 579 return null; 580 } 581 582 583 /*** 584 * Fetches the help information for a given command from the server and 585 * returns the full string. 586 * <p> 587 * @param command The command on which to ask for help. 588 * @return The command help string obtained from the server. null if the 589 * information could not be obtained. 590 * @exception SMTPConnectionClosedException 591 * If the SMTP server prematurely closes the connection as a result 592 * of the client being idle or some other reason causing the server 593 * to send SMTP reply code 421. This exception may be caught either 594 * as an IOException or independently as itself. 595 * @exception IOException If an I/O error occurs while either sending a 596 * command to the server or receiving a reply from the server. 597 ***/ 598 public String listHelp(String command) throws IOException 599 { 600 if (SMTPReply.isPositiveCompletion(help(command))) { 601 return getReplyString(); 602 } 603 return null; 604 } 605 606 607 /*** 608 * Sends a NOOP command to the SMTP server. This is useful for preventing 609 * server timeouts. 610 * <p> 611 * @return True if successfully completed, false if not. 612 * @exception SMTPConnectionClosedException 613 * If the SMTP server prematurely closes the connection as a result 614 * of the client being idle or some other reason causing the server 615 * to send SMTP reply code 421. This exception may be caught either 616 * as an IOException or independently as itself. 617 * @exception IOException If an I/O error occurs while either sending a 618 * command to the server or receiving a reply from the server. 619 ***/ 620 public boolean sendNoOp() throws IOException 621 { 622 return SMTPReply.isPositiveCompletion(noop()); 623 } 624 625}