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 018 package org.apache.commons.net.smtp; 019 020 import java.io.IOException; 021 import java.io.Writer; 022 import java.net.InetAddress; 023 024 import 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 * <p> 117 * <p> 118 * @see SMTP 119 * @see SimpleSMTPHeader 120 * @see RelayPath 121 * @see SMTPConnectionClosedException 122 * @see org.apache.commons.net.MalformedServerReplyException 123 ***/ 124 125 public class SMTPClient extends SMTP 126 { 127 128 /** 129 * Default SMTPClient constructor. Creates a new SMTPClient instance. 130 */ 131 public SMTPClient() { } 132 133 /** 134 * Overloaded constructor that takes an encoding specification 135 * @param encoding The encoding to use 136 * @since 2.0 137 */ 138 public SMTPClient(String encoding) { 139 super(encoding); 140 } 141 142 143 /*** 144 * At least one SMTPClient method ({@link #sendMessageData sendMessageData }) 145 * does not complete the entire sequence of SMTP commands to complete a 146 * transaction. These types of commands require some action by the 147 * programmer after the reception of a positive intermediate command. 148 * After the programmer's code completes its actions, it must call this 149 * method to receive the completion reply from the server and verify the 150 * success of the entire transaction. 151 * <p> 152 * For example, 153 * <pre> 154 * writer = client.sendMessage(); 155 * if(writer == null) // failure 156 * return false; 157 * header = 158 * new SimpleSMTPHeader("foobar@foo.com", "foo@foobar.com", "Re: Foo"); 159 * writer.write(header.toString()); 160 * writer.write("This is just a test"); 161 * writer.close(); 162 * if(!client.completePendingCommand()) // failure 163 * return false; 164 * </pre> 165 * <p> 166 * @return True if successfully completed, false if not. 167 * @exception SMTPConnectionClosedException 168 * If the SMTP server prematurely closes the connection as a result 169 * of the client being idle or some other reason causing the server 170 * to send SMTP reply code 421. This exception may be caught either 171 * as an IOException or independently as itself. 172 * @exception IOException If an I/O error occurs while either sending a 173 * command to the server or receiving a reply from the server. 174 ***/ 175 public boolean completePendingCommand() throws IOException 176 { 177 return SMTPReply.isPositiveCompletion(getReply()); 178 } 179 180 181 /*** 182 * Login to the SMTP server by sending the HELO command with the 183 * given hostname as an argument. Before performing any mail commands, 184 * you must first login. 185 * <p> 186 * @param hostname The hostname with which to greet the SMTP server. 187 * @return True if successfully completed, false if not. 188 * @exception SMTPConnectionClosedException 189 * If the SMTP server prematurely closes the connection as a result 190 * of the client being idle or some other reason causing the server 191 * to send SMTP reply code 421. This exception may be caught either 192 * as an IOException or independently as itself. 193 * @exception IOException If an I/O error occurs while either sending a 194 * command to the server or receiving a reply from the server. 195 ***/ 196 public boolean login(String hostname) throws IOException 197 { 198 return SMTPReply.isPositiveCompletion(helo(hostname)); 199 } 200 201 202 /*** 203 * Login to the SMTP server by sending the HELO command with the 204 * client hostname as an argument. Before performing any mail commands, 205 * you must first login. 206 * <p> 207 * @return True if successfully completed, false if not. 208 * @exception SMTPConnectionClosedException 209 * If the SMTP server prematurely closes the connection as a result 210 * of the client being idle or some other reason causing the server 211 * to send SMTP reply code 421. This exception may be caught either 212 * as an IOException or independently as itself. 213 * @exception IOException If an I/O error occurs while either sending a 214 * command to the server or receiving a reply from the server. 215 ***/ 216 public boolean login() throws IOException 217 { 218 String name; 219 InetAddress host; 220 221 host = getLocalAddress(); 222 name = host.getHostName(); 223 224 if (name == null) { 225 return false; 226 } 227 228 return SMTPReply.isPositiveCompletion(helo(name)); 229 } 230 231 232 /*** 233 * Set the sender of a message using the SMTP MAIL command, specifying 234 * a reverse relay path. The sender must be set first before any 235 * recipients may be specified, otherwise the mail server will reject 236 * your commands. 237 * <p> 238 * @param path The reverse relay path pointing back to the sender. 239 * @return True if successfully completed, false if not. 240 * @exception SMTPConnectionClosedException 241 * If the SMTP server prematurely closes the connection as a result 242 * of the client being idle or some other reason causing the server 243 * to send SMTP reply code 421. This exception may be caught either 244 * as an IOException or independently as itself. 245 * @exception IOException If an I/O error occurs while either sending a 246 * command to the server or receiving a reply from the server. 247 ***/ 248 public boolean setSender(RelayPath path) throws IOException 249 { 250 return SMTPReply.isPositiveCompletion(mail(path.toString())); 251 } 252 253 254 /*** 255 * Set the sender of a message using the SMTP MAIL command, specifying 256 * the sender's email address. The sender must be set first before any 257 * recipients may be specified, otherwise the mail server will reject 258 * your commands. 259 * <p> 260 * @param address The sender's email address. 261 * @return True if successfully completed, false if not. 262 * @exception SMTPConnectionClosedException 263 * If the SMTP server prematurely closes the connection as a result 264 * of the client being idle or some other reason causing the server 265 * to send SMTP reply code 421. This exception may be caught either 266 * as an IOException or independently as itself. 267 * @exception IOException If an I/O error occurs while either sending a 268 * command to the server or receiving a reply from the server. 269 ***/ 270 public boolean setSender(String address) throws IOException 271 { 272 return SMTPReply.isPositiveCompletion(mail("<" + address + ">")); 273 } 274 275 276 /*** 277 * Add a recipient for a message using the SMTP RCPT command, specifying 278 * a forward relay path. The sender must be set first before any 279 * recipients may be specified, otherwise the mail server will reject 280 * your commands. 281 * <p> 282 * @param path The forward relay path pointing to the recipient. 283 * @return True if successfully completed, false if not. 284 * @exception SMTPConnectionClosedException 285 * If the SMTP server prematurely closes the connection as a result 286 * of the client being idle or some other reason causing the server 287 * to send SMTP reply code 421. This exception may be caught either 288 * as an IOException or independently as itself. 289 * @exception IOException If an I/O error occurs while either sending a 290 * command to the server or receiving a reply from the server. 291 ***/ 292 public boolean addRecipient(RelayPath path) throws IOException 293 { 294 return SMTPReply.isPositiveCompletion(rcpt(path.toString())); 295 } 296 297 298 /*** 299 * Add a recipient for a message using the SMTP RCPT command, the 300 * recipient's email address. The sender must be set first before any 301 * recipients may be specified, otherwise the mail server will reject 302 * your commands. 303 * <p> 304 * @param address The recipient's email address. 305 * @return True if successfully completed, false if not. 306 * @exception SMTPConnectionClosedException 307 * If the SMTP server prematurely closes the connection as a result 308 * of the client being idle or some other reason causing the server 309 * to send SMTP reply code 421. This exception may be caught either 310 * as an IOException or independently as itself. 311 * @exception IOException If an I/O error occurs while either sending a 312 * command to the server or receiving a reply from the server. 313 ***/ 314 public boolean addRecipient(String address) throws IOException 315 { 316 return SMTPReply.isPositiveCompletion(rcpt("<" + address + ">")); 317 } 318 319 320 321 /*** 322 * Send the SMTP DATA command in preparation to send an email message. 323 * This method returns a DotTerminatedMessageWriter instance to which 324 * the message can be written. Null is returned if the DATA command 325 * fails. 326 * <p> 327 * You must not issue any commands to the SMTP server (i.e., call any 328 * (other methods) until you finish writing to the returned Writer 329 * instance and close it. The SMTP protocol uses the same stream for 330 * issuing commands as it does for returning results. Therefore the 331 * returned Writer actually writes directly to the SMTP connection. 332 * After you close the writer, you can execute new commands. If you 333 * do not follow these requirements your program will not work properly. 334 * <p> 335 * You can use the provided 336 * {@link org.apache.commons.net.smtp.SimpleSMTPHeader} 337 * class to construct a bare minimum header. 338 * To construct more complicated headers you should 339 * refer to RFC 822. When the Java Mail API is finalized, you will be 340 * able to use it to compose fully compliant Internet text messages. 341 * The DotTerminatedMessageWriter takes care of doubling line-leading 342 * dots and ending the message with a single dot upon closing, so all 343 * you have to worry about is writing the header and the message. 344 * <p> 345 * Upon closing the returned Writer, you need to call 346 * {@link #completePendingCommand completePendingCommand() } 347 * to finalize the transaction and verify its success or failure from 348 * the server reply. 349 * <p> 350 * @return A DotTerminatedMessageWriter to which the message (including 351 * header) can be written. Returns null if the command fails. 352 * @exception SMTPConnectionClosedException 353 * If the SMTP server prematurely closes the connection as a result 354 * of the client being idle or some other reason causing the server 355 * to send SMTP reply code 421. This exception may be caught either 356 * as an IOException or independently as itself. 357 * @exception IOException If an I/O error occurs while either sending a 358 * command to the server or receiving a reply from the server. 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 * @return True if successfully completed, false if not. 380 * @exception SMTPConnectionClosedException 381 * If the SMTP server prematurely closes the connection as a result 382 * of the client being idle or some other reason causing the server 383 * to send SMTP reply code 421. This exception may be caught either 384 * as an IOException or independently as itself. 385 * @exception IOException If an I/O error occurs while either sending a 386 * command to the server or receiving a reply from the server. 387 ***/ 388 public boolean sendShortMessageData(String message) throws IOException 389 { 390 Writer writer; 391 392 writer = sendMessageData(); 393 394 if (writer == null) { 395 return false; 396 } 397 398 writer.write(message); 399 writer.close(); 400 401 return completePendingCommand(); 402 } 403 404 405 /*** 406 * A convenience method for a sending short email without having to 407 * explicitly set the sender and recipient(s). This method 408 * sets the sender and recipient using 409 * {@link #setSender setSender } and 410 * {@link #addRecipient addRecipient }, and then sends the 411 * message using {@link #sendShortMessageData sendShortMessageData }. 412 * <p> 413 * @param sender The email address of the sender. 414 * @param recipient The email address of the recipient. 415 * @param message The short email message to send. 416 * @return True if successfully completed, false if not. 417 * @exception SMTPConnectionClosedException 418 * If the SMTP server prematurely closes the connection as a result 419 * of the client being idle or some other reason causing the server 420 * to send SMTP reply code 421. This exception may be caught either 421 * as an IOException or independently as itself. 422 * @exception IOException If an I/O error occurs while either sending a 423 * command to the server or receiving a reply from the server. 424 ***/ 425 public boolean sendSimpleMessage(String sender, String recipient, 426 String message) 427 throws IOException 428 { 429 if (!setSender(sender)) { 430 return false; 431 } 432 433 if (!addRecipient(recipient)) { 434 return false; 435 } 436 437 return sendShortMessageData(message); 438 } 439 440 441 442 /*** 443 * A convenience method for a sending short email without having to 444 * explicitly set the sender and recipient(s). This method 445 * sets the sender and recipients using 446 * {@link #setSender setSender } and 447 * {@link #addRecipient addRecipient }, and then sends the 448 * message using {@link #sendShortMessageData sendShortMessageData }. 449 * <p> 450 * @param sender The email address of the sender. 451 * @param recipients An array of recipient email addresses. 452 * @param message The short email message to send. 453 * @return True if successfully completed, false if not. 454 * @exception SMTPConnectionClosedException 455 * If the SMTP server prematurely closes the connection as a result 456 * of the client being idle or some other reason causing the server 457 * to send SMTP reply code 421. This exception may be caught either 458 * as an IOException or independently as itself. 459 * @exception IOException If an I/O error occurs while either sending a 460 * command to the server or receiving a reply from the server. 461 ***/ 462 public boolean sendSimpleMessage(String sender, String[] recipients, 463 String message) 464 throws IOException 465 { 466 boolean oneSuccess = false; 467 int count; 468 469 if (!setSender(sender)) { 470 return false; 471 } 472 473 for (count = 0; count < recipients.length; count++) 474 { 475 if (addRecipient(recipients[count])) { 476 oneSuccess = true; 477 } 478 } 479 480 if (!oneSuccess) { 481 return false; 482 } 483 484 return sendShortMessageData(message); 485 } 486 487 488 /*** 489 * Logout of the SMTP server by sending the QUIT command. 490 * <p> 491 * @return True if successfully completed, false if not. 492 * @exception SMTPConnectionClosedException 493 * If the SMTP server prematurely closes the connection as a result 494 * of the client being idle or some other reason causing the server 495 * to send SMTP reply code 421. This exception may be caught either 496 * as an IOException or independently as itself. 497 * @exception IOException If an I/O error occurs while either sending a 498 * command to the server or receiving a reply from the server. 499 ***/ 500 public boolean logout() throws IOException 501 { 502 return SMTPReply.isPositiveCompletion(quit()); 503 } 504 505 506 507 /*** 508 * Aborts the current mail transaction, resetting all server stored 509 * sender, recipient, and mail data, cleaing all buffers and tables. 510 * <p> 511 * @return True if successfully completed, false if not. 512 * @exception SMTPConnectionClosedException 513 * If the SMTP server prematurely closes the connection as a result 514 * of the client being idle or some other reason causing the server 515 * to send SMTP reply code 421. This exception may be caught either 516 * as an IOException or independently as itself. 517 * @exception IOException If an I/O error occurs while either sending a 518 * command to the server or receiving a reply from the server. 519 ***/ 520 public boolean reset() throws IOException 521 { 522 return SMTPReply.isPositiveCompletion(rset()); 523 } 524 525 526 /*** 527 * Verify that a username or email address is valid, i.e., that mail 528 * can be delivered to that mailbox on the server. 529 * <p> 530 * @param username The username or email address to validate. 531 * @return True if the username is valid, false if not. 532 * @exception SMTPConnectionClosedException 533 * If the SMTP server prematurely closes the connection as a result 534 * of the client being idle or some other reason causing the server 535 * to send SMTP reply code 421. This exception may be caught either 536 * as an IOException or independently as itself. 537 * @exception IOException If an I/O error occurs while either sending a 538 * command to the server or receiving a reply from the server. 539 ***/ 540 public boolean verify(String username) throws IOException 541 { 542 int result; 543 544 result = vrfy(username); 545 546 return (result == SMTPReply.ACTION_OK || 547 result == SMTPReply.USER_NOT_LOCAL_WILL_FORWARD); 548 } 549 550 551 /*** 552 * Fetches the system help information from the server and returns the 553 * full string. 554 * <p> 555 * @return The system help string obtained from the server. null if the 556 * information could not be obtained. 557 * @exception SMTPConnectionClosedException 558 * If the SMTP server prematurely closes the connection as a result 559 * of the client being idle or some other reason causing the server 560 * to send SMTP reply code 421. This exception may be caught either 561 * as an IOException or independently as itself. 562 * @exception IOException If an I/O error occurs while either sending a 563 * command to the server or receiving a reply from the server. 564 ***/ 565 public String listHelp() throws IOException 566 { 567 if (SMTPReply.isPositiveCompletion(help())) { 568 return getReplyString(); 569 } 570 return null; 571 } 572 573 574 /*** 575 * Fetches the help information for a given command from the server and 576 * returns the full string. 577 * <p> 578 * @param command The command on which to ask for help. 579 * @return The command help string obtained from the server. null if the 580 * information could not be obtained. 581 * @exception SMTPConnectionClosedException 582 * If the SMTP server prematurely closes the connection as a result 583 * of the client being idle or some other reason causing the server 584 * to send SMTP reply code 421. This exception may be caught either 585 * as an IOException or independently as itself. 586 * @exception IOException If an I/O error occurs while either sending a 587 * command to the server or receiving a reply from the server. 588 ***/ 589 public String listHelp(String command) throws IOException 590 { 591 if (SMTPReply.isPositiveCompletion(help(command))) { 592 return getReplyString(); 593 } 594 return null; 595 } 596 597 598 /*** 599 * Sends a NOOP command to the SMTP server. This is useful for preventing 600 * server timeouts. 601 * <p> 602 * @return True if successfully completed, false if not. 603 * @exception SMTPConnectionClosedException 604 * If the SMTP server prematurely closes the connection as a result 605 * of the client being idle or some other reason causing the server 606 * to send SMTP reply code 421. This exception may be caught either 607 * as an IOException or independently as itself. 608 * @exception IOException If an I/O error occurs while either sending a 609 * command to the server or receiving a reply from the server. 610 ***/ 611 public boolean sendNoOp() throws IOException 612 { 613 return SMTPReply.isPositiveCompletion(noop()); 614 } 615 616 }