用JavaMail发送带附件的邮件

AI权益加码!Claude Code、Cursor等20+工具免费用! 购周边限时加赠Coding Plan Lite,畅享主流AI工具!学习进阶更高效! 阅读详情

本文根据Ian F. Darwin的《Java Cookbook》整理而成,原书用整章的文字介绍如何发邮件,可能头绪会比较乱,本文则将其浓缩成一篇文章,力求使完全不懂JavaMail的人,都可以根据文中指示稍作修改,拿来就可以用。如果对其中原理还有不清楚,你可以参考原书。

一、首先要用到三个java文件:

1.MailConstants.java,properties文件的助记符:
///////////////////////////////////////////////////////////////////////
package untitled2;

/** Simply a list of names for the Mail System to use.
 * If you "implement" this interface, you don't have to prefix
 * all the names with MailProps in your code.
 */
public interface MailConstants {
  public static final String PROPS_FILE_NAME = "MailClient.properties";

  public static final String SEND_PROTO = "Mail.send.protocol";
  public static final String SEND_USER = "Mail.send.user";
  public static final String SEND_PASS = "Mail.send.password";
  public static final String SEND_ROOT = "Mail.send.root";
  public static final String SEND_HOST = "Mail.send.host";
  public static final String SEND_DEBUG = "Mail.send.debug";

  public static final String RECV_PROTO = "Mail.receive.protocol";
  public static final String RECV_PORT = "Mail.receive.port";
  public static final String RECV_USER = "Mail.receive.user";
  public static final String RECV_PASS = "Mail.receive.password";
  public static final String RECV_ROOT = "Mail.receive.root";
  public static final String RECV_HOST = "Mail.receive.host";
  public static final String RECV_DEBUG = "Mail.receive.debug";
}
///////////////////////////////////////////////////////////////////////

2.FileProperties.java,从文件中读取properties:
///////////////////////////////////////////////////////////////////////
package untitled2;

import java.io.*;
import java.util.*;

/**
 * The <CODE>FileProperties</CODE> class extends <CODE>Properties</CODE>,
 * "a persistent set of properties [that] can be saved to a stream
 * or loaded from a stream". This subclass attends to all the mundane
 * details of opening the Stream(s) for actually saving and loading
 * the Properties.
 *
 * <P>This subclass preserves the useful feature that
 * a property list can contain another property list as its
 * "defaults"; this second property list is searched if
 * the property key is not found in the original property list.
 *
 * @author Ian F. Darwin,
ian@darwinsys.com
 * @version $Id: FileProperties.java,v 1.5 2001/04/28 13:22:37 ian Exp $
 */
public class FileProperties
    extends Properties {
  protected String fileName = null;

  /**
   *  Construct a FileProperties given a fileName.
   *  @param loadsaveFileName the progerties file name
   *  @throws IOException
   */
  public FileProperties(String loadsaveFileName) throws IOException {
    super();
    fileName = loadsaveFileName;
    load();
  }

  /** Construct a FileProperties given a fileName and
   * a list of default properties.
   * @param loadsaveFileName the properties file name
   * @param defProp the default properties
   * @throws IOException
   */
  public FileProperties(String loadsaveFileName, Properties defProp) throws
      IOException {
    super(defProp);
    fileName = loadsaveFileName;
    load();
  }

  /** The InputStream for loading */
  protected InputStream inStr = null;

  /** The OutputStream for loading */
  protected OutputStream outStr = null;

  /** Load the properties from the saved filename.
   * If that fails, try again, tacking on the .properties extension
   * @throws IOException
   */
  public void load() throws IOException {
    try {
      if (inStr == null) {
        inStr = new FileInputStream(fileName);
      }
    }
    catch (FileNotFoundException fnf) {
      if (!fileName.endsWith(".properties")) {
        inStr = new FileInputStream(fileName + ".properties");
        // If we succeeded, remember it:
        fileName += ".properties";
      }
      else {

        // It did end with .properties and failed, re-throw exception.
        throw fnf;
      }
    }
    // now message the superclass code to load the file.
    load(inStr);
  }

  /** Save the properties for later loading. *
   *  @throws IOException
   */

  public void save() throws IOException {
    if (outStr == null) {
      outStr = new FileOutputStream(fileName);
    }
    // Get the superclass to do most of the work for us.
    store(outStr, "# Written by FileProperties.save() at " + new Date());
  }

  public void close() {
    try {
      if (inStr != null) {
        inStr.close();
      }
      if (outStr != null) {
        outStr.close();
      }
    }
    catch (IOException e) {
      // don't care
    }
  }
}
///////////////////////////////////////////////////////////////////////

3.Mailer.java,将javamail发邮件的部分进行封装:
///////////////////////////////////////////////////////////////////////
package untitled2;

import java.util.*;
import java.io.*;
import javax.mail.*;
import javax.mail.internet.*;
import javax.activation.*;

public class Mailer {
  /** The javamail session object. */
  protected Session session;
  /** The sender's email address */
  protected String from;
  /** The subject of the message. */
  protected String subject;
  /** The recipient ("To:"), as Strings. */
  protected ArrayList toList = new ArrayList();
  /** The CC list, as Strings. */
  protected ArrayList ccList = new ArrayList();
  /** The BCC list, as Strings. */
  protected ArrayList bccList = new ArrayList();
  /** The text of the message. */
  protected String body;
  /** The SMTP relay host */
  protected String mailHost;
  /** The accessories list, as Strings.*/
  protected ArrayList accessories = new ArrayList();
  /** The verbosity setting */
  protected boolean verbose;

  /** Get from
   * @return where the mail from
   */
  public String getFrom() {
    return from;
  }

  /** Set from
   * @param fm where the mail from
   */
  public void setFrom(String fm) {
    from = fm;
  }

  /** Get subject
   * @return the mail subject
   */
  public String getSubject() {
    return subject;
  }

  /** Set subject
   * @param subj the mail subject
   */
  public void setSubject(String subj) {
    subject = subj;
  }

  // SETTERS/GETTERS FOR TO: LIST

  /** Get tolist, as an array of Strings
   * @return the list of toAddress
   */
  public ArrayList getToList() {
    return toList;
  }

  /** Set to list to an ArrayList of Strings
   * @param to the list of toAddress
   */
  public void setToList(ArrayList to) {
    toList = to;
  }

  /** Set to as a string like "tom, mary, robin@host". Loses any
   * previously-set values.
   * @param s the list of toAddress*/
  public void setToList(String s) {
    toList = tokenize(s);
  }

  /** Add one "to" recipient
   * @param to the toAddress
   */
  public void addTo(String to) {
    toList.add(to);
  }

  // SETTERS/GETTERS FOR CC: LIST

  /** Get cclist, as an array of Strings
   * @return the list of ccAddress
   */
  public ArrayList getCcList() {
    return ccList;
  }

  /** Set cc list to an ArrayList of Strings
   * @param cc the list of ccAddress
   */
  public void setCcList(ArrayList cc) {
    ccList = cc;
  }

  /** Set cc as a string like "tom, mary, robin@host". Loses any
   * previously-set values.
   * @param s the list of ccAddress
   */
  public void setCcList(String s) {
    ccList = tokenize(s);
  }

  /** Add one "cc" recipient
   * @param cc the address of cc
   */
  public void addCc(String cc) {
    ccList.add(cc);
  }

  // SETTERS/GETTERS FOR BCC: LIST

  /** Get bcclist, as an array of Strings
   * @return the list of bcc
   */
  public ArrayList getBccList() {
    return bccList;
  }

  /** Set bcc list to an ArrayList of Strings
   * @param bcc the address of bcc
   */
  public void setBccList(ArrayList bcc) {
    bccList = bcc;
  }

  /** Set bcc as a string like "tom, mary, robin@host". Loses any
   * previously-set values.
   * @param s the address of bcc
   */
  public void setBccList(String s) {
    bccList = tokenize(s);
  }

  /** Add one "bcc" recipient
   * @param bcc the address of bcc
   */
  public void addBcc(String bcc) {
    bccList.add(bcc);
  }

  // SETTER/GETTER FOR MESSAGE BODY

  /** Get message
   * @return the mail body
   */
  public String getBody() {
    return body;
  }

  /** Set message
   * @param text the mail body
   */
  public void setBody(String text) {
    body = text;
  }

  // SETTER/GETTER FOR ACCESSORIES

  /** Get accessories
   * @return the arrayList of the accessories
   */
  public ArrayList getAccessories() {
    return accessories;
  }

  /** Set accessories
   * @param accessories the arrayList of the accessories
   */
  public void setAccessories(ArrayList accessories) {
    this.accessories = accessories;
  }

  // SETTER/GETTER FOR VERBOSITY

  /** Get verbose
   * @return verbose
   */
  public boolean isVerbose() {
    return verbose;
  }

  /** Set verbose
   * @param v the verbose
   */
  public void setVerbose(boolean v) {
    verbose = v;
  }

  /** Check if all required fields have been set before sending.
   * Normally called e.g., by a JSP before calling doSend.
   * Is also called by doSend for verification.
   * @return if complete return true else return false
   */
  public boolean isComplete() {
    if (from == null || from.length() == 0) {
      System.err.println("doSend: no FROM");
      return false;
    }
    if (subject == null || subject.length() == 0) {
      System.err.println("doSend: no SUBJECT");
      return false;
    }
    if (toList.size() == 0) {
      System.err.println("doSend: no recipients");
      return false;
    }
    if (body == null || body.length() == 0) {
      System.err.println("doSend: no body");
      return false;
    }
    if (mailHost == null || mailHost.length() == 0) {
      System.err.println("doSend: no server host");
      return false;
    }
    return true;
  }

  public void setServer(String s) {
    mailHost = s;
  }

  /** Send the message.
   * @throws MessagingException
   */
  public synchronized void doSend() throws MessagingException {

    if (!isComplete()) {
      throw new IllegalArgumentException(
          "doSend called before message was complete");
    }

    /** Properties object used to pass props into the MAIL API */
    Properties props = new Properties();
    props.put("mail.smtp.host", mailHost);

    // Create the Session object
    if (session == null) {
      session = Session.getDefaultInstance(props, null);
      if (verbose) {
        session.setDebug(true); // Verbose!
      }
    }

    // create a message
    final Message mesg = new MimeMessage(session);

    InternetAddress[] addresses;

    // TO Address list
    addresses = new InternetAddress[toList.size()];
    for (int i = 0; i < addresses.length; i++) {
      addresses[i] = new InternetAddress( (String) toList.get(i));
    }
    mesg.setRecipients(Message.RecipientType.TO, addresses);

    // From Address
    mesg.setFrom(new InternetAddress(from));

    // CC Address list
    addresses = new InternetAddress[ccList.size()];
    for (int i = 0; i < addresses.length; i++) {
      addresses[i] = new InternetAddress( (String) ccList.get(i));
    }
    mesg.setRecipients(Message.RecipientType.CC, addresses);

    // BCC Address list
    addresses = new InternetAddress[bccList.size()];
    for (int i = 0; i < addresses.length; i++) {
      addresses[i] = new InternetAddress( (String) bccList.get(i));
    }
    mesg.setRecipients(Message.RecipientType.BCC, addresses);

    // The Subject
    mesg.setSubject(subject);

    // Now the message body.
    Multipart mp = new MimeMultipart();
    MimeBodyPart mbp = null;
    mbp = new MimeBodyPart();
    mbp.setText(body);
    mp.addBodyPart(mbp);

    // Now the accessories.
    int accessoriesCount = accessories.size();
    File f;
    DataSource ds;
    String uf;
    int j;
    for (int i = 0; i < accessoriesCount; i++) {
      mbp = new MimeBodyPart();
      f = new File( (String) accessories.get(i));
      ds = new FileDataSource(f);
      mbp.setDataHandler(new DataHandler(ds));
      j = f.getName().lastIndexOf(File.separator);
      uf = f.getName().substring(j + 1);
      mbp.setFileName(uf);
      mp.addBodyPart(mbp);
    }

    mesg.setContent(mp);

    // Finally, send the message! (use static Transport method)
    // Do this in a Thread as it sometimes is too slow for JServ
    // new Thread() {
    // public void run() {
    // try {

    Transport.send(mesg);

    // } catch (MessagingException e) {
    // throw new IllegalArgumentException(
    // "Transport.send() threw: " + e.toString());
    // }
    // }
    // }.start();
  }

  /** Convenience method that does it all with one call.
   * @param mailhost - SMTP server host
   * @param recipient - domain address of email (
user@host.domain)
   * @param sender - your email address
   * @param subject - the subject line
   * @param message - the entire message body as a String with embedded /n's
   * @param accessories - the accessories list
   * @throws MessagingException
   */
  public static void send(String mailhost,
                          String recipient, String sender, String subject,
                          String message, ArrayList accessories) throws
      MessagingException {
    Mailer m = new Mailer();
    m.setServer(mailhost);
    m.addTo(recipient);
    m.setFrom(sender);
    m.setSubject(subject);
    m.setBody(message);
    m.setAccessories(accessories);
    m.doSend();
  }

  /** Convert a list of addresses to an ArrayList. This will work
   * for simple names like "tom,
mary@foo.com, 123.45@c$.com"
   * but will fail on certain complex (but RFC-valid) names like
   * "(Darwin, Ian) <
ian@darwinsys.com>".
   * Or even "Ian Darwin <
ian@darwinsys.com>".
   * @param s the string of some list
   * @return the list after split
   */
  protected ArrayList tokenize(String s) {
    ArrayList al = new ArrayList();
    StringTokenizer tf = new StringTokenizer(s, ",");
    // For each word found in the line
    while (tf.hasMoreTokens()) {
      // trim blanks, and add to list.
      al.add(tf.nextToken().trim());
    }
    return al;
  }
}
///////////////////////////////////////////////////////////////////////

二、创建一个properties文件:

MailClient.properties:
///////////////////////////////////////////////////////////////////////
# This file contains my default Mail properties.
#
# Values for sending
Mail.address=xx@zsu.edu.cn
Mail.send.proto=smtp
Mail.send.host=student.zsu.edu.cn
Mail.send.debug=true
#
# Values for receiving
Mail.receive.host=student.zsu.edu.cn
Mail.receive.protocol=pop3
Mail.receive.user=xx
Mail.receive.pass=ASK
Mail.receive.root=d:/test
///////////////////////////////////////////////////////////////////////

三、创建主程序,生成Mailer.java里面的Mailer类的对象,设置参数,发出邮件。

首先import:
///////////////////////////////////////////////////////////////////////
import java.io.*;
import java.util.*;
import javax.mail.internet.*;
import javax.mail.*;
import javax.activation.*;
///////////////////////////////////////////////////////////////////////

然后用下面的代码完成发送:
///////////////////////////////////////////////////////////////////////
    try {
      Mailer m = new Mailer();

      FileProperties props =
          new FileProperties(MailConstants.PROPS_FILE_NAME);
      String serverHost = props.getProperty(MailConstants.SEND_HOST);
      if (serverHost == null) {
        System.out.println("/"" + MailConstants.SEND_HOST +
                                      "/" must be set in properties");
        System.exit(0);
      }
      m.setServer(serverHost);

      String tmp = props.getProperty(MailConstants.SEND_DEBUG);
      m.setVerbose(tmp != null && tmp.equals("true"));

      String myAddress = props.getProperty("Mail.address");
      if (myAddress == null) {
        System.out.println("/"Mail.address/" must be set in properties");
        System.exit(0);
      }
      m.setFrom(myAddress);

//以下根据具体情况设置:===============================================
      m.setToList("
xx@zsu.edu.cn");//收件人
      m.setCcList("
xx@163.com,yy@163.com");//抄送,每个地址用逗号隔开;或者用一个ArrayList的对象作为参数
      // m.setBccList(bccTF.getText());

      m.setSubject("demo");//主题

      // Now copy the text from the Compose TextArea.
      m.setBody("this is a demo");//正文
      // XXX I18N: use setBody(msgText.getText(), charset)
     
      ArrayList v=new ArrayList();
      v.add("d://test.htm"); 
      m.setAccessories(v);//附件
//以上根据具体情况设置=================================================
      // Finally, send the sucker!
      m.doSend();

    }
    catch (MessagingException me) {
      me.printStackTrace();
      while ( (me = (MessagingException) me.getNextException()) != null) {
        me.printStackTrace();
      }
      System.out.println("Mail Sending Error:/n" + me.toString());
    }
    catch (Exception ex) {
      System.out.println("Mail Sending Error:/n" + ex.toString());
    }
///////////////////////////////////////////////////////////////////////

使用javaMail发送文本邮件附件邮件以及android后台发送邮件 一、使用javamail发送普通文本邮件 发送电子邮件 主要步骤如下: 1,获取系统Properties. Properties props = System.getProperties(); 2,将您的SMTP服务器名添加到mail.smtp.host关键字的属性中. Props.pout( “ mail.smtp.host ” ,host); 3,获取基于Prop 阅读详情

相关推荐

JavaMail 网易邮件发送demo-发送附件邮件

JavaMail 网易邮件发送demo-发送附件邮件

joshua317的博客 1401

simple-java-mail:简单API,复杂电子邮件JavaMail smtp包装器)

简单的Java邮件 简单Java邮件是使用最简单的轻量级Java邮件库,同时能够发送复杂的电子邮件,包括,经过(!),,,, ,,甚至, 和具有属性覆盖的, 和工具。 只需发送电子邮件即可,而无需处理 。 Simple Java Mail库是之上的一薄层,它使用户可以以较高的抽象级别定义电子邮件,而不必处理诸如“ multipart”和“ mimemessage”之类的庞然大物。 也提供了简单Java Mail: < dependency> < groupId>org.simplejavamail</ groupId> < artifactId>simple-ja

使用JavaMail在Android中发送附件邮件

通过使用JavaMail库,您可以在Android应用程序中方便地发送附件的电子邮件。您需要添加JavaMail的依赖项,并设置适当的权限。然后,创建一个发送邮件的方法,并在需要发送邮件的地方调用该方法。在Android应用程序中,我们经常需要发送电子邮件,有时候还需要附加文件。JavaMail是一个强大的库,它提供了发送和接收电子邮件的功能。首先,您需要在您的Android项目中添加JavaMail的依赖项。现在,您可以在您的Android应用程序中的适当位置调用。在上面的代码中,您需要将。

DevGOOD的博客 327

【亲测免费】 推荐开源项目:Simple Java Mail,让邮件发送变得轻松简单!

Simple Java Mail 是一个轻量级的Java库,它在复杂电子邮件发送上提供了极大的便利性。该项目的目标是简化邮件处理过程,让用户无需了解底层的[RFCs](https://www.simplejavamail.org/rfc-compliant.html#navigation),只需关注邮件内容即可轻松发送邮件。该库基于 Jakarta Mail 进行构建,并提供了一系列高级特性,如...

gitblog_00026的博客 1586

Simple Java Mail的使用,发送qq邮件

Simple Java Mail的使用,发送qq邮件第一步 开启SMTP服务第二步 导入jar包第三步 代码实现 第一步 开启SMTP服务 打开qq邮箱,设置-账户 开启SMTP服务,拿到授权码 第二步 导入jar包 Simple Java Mail是一个非常强大的邮件发送框架,非常值得使用。 官方网站: http://www.simplejavamail.org/#/about. // An highlighted block <!-- 邮件发送 -->

钓瞄的鱼的博客 987

Simple Java Mail的使用

Simple Java Mail是一个非常强大的邮件发送框架,非常值得使用。本文翻译Simple Java Mail的官方实例文档,可以参考使用。原文: http://www.simplejavamail.org/#/features基本用法创建Email,填充你的数据,创建Mailer然后发送Email实例,mailer也可以是你自己的Session实例。 Mailer 是单例模式。Email e

flash_love的博客 7071

simple java mail

1 <dependency> 2 <groupId>org.simplejavamail</groupId> 3 <artifactId>simple-java-mail</artifactId> 4 <version>5.1.3</version> 5 </depende...

weixin_30765505的博客 219

JavaMail发送图片,附件邮件

JavaMail发送图片,附件邮件 简介 上一篇文章讲到了使用JavaMail来实现简单邮件发送,这篇文章是在上一篇文章的基础上来完成的。 导入jar包 <dependency> <groupId>javax.activation</groupId> <artifactId>activation</artifac...

qq_43419105的博客 2733

JavaMail API编写可附件邮件发送程序

利用Sun公司提供的JavaMail API可以很方便的开发邮件发送程序。也许你已经可以利用它来发送一段简单的文本了,但想不想使你的程序像OUTLOOK一样也能发送附件呢?本文在简单介绍了JavaMail之后,详细讲解了一段完整的送信的JavaBean及一个十分轻巧的servlet。 (没有装载JavaMail API的读者,可以到此站点下载,并按照Readme.txt设置好ClassPath

编程の浪子的专栏 2200

JavaMail发送附件的电子邮件示例

<br />/** * CrazyItTest * 使用JavaMail发送附件的电子邮件示例 */ package com.labci.javamail.test; import java.io.FileNotFoundException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.Date; import java.util.Properti

6526

JavaMail附件邮件发送

发送纯文本的邮件 package com.haiwen.test; import java.util.Date; import java.util.Properties; import javax.mail.Message.RecipientType; import javax.mail.Session; import javax.mail.Transport; import javax....

离开屏幕的光,哪盏灯照亮你的孤独? 1万+

Javamail 发送附件邮件

使用时,要注意与其它mail包的冲突问题,如geronimo-javamail_1.4_spec-1.3.jar会导致邮件发出去的都是编码数据 import java.util.Date; import java.util.Properties; import javax.activation.DataHandler;import javax.activation.FileDataSourc...

自由时飞扬 搬家拉 http://www.meiriyouke.net 318

JavaMail 发送图片和附件)和接收邮件

目录 1、JavaMail 介绍 2、JavaMail API 3、使用 JavaMail 发送简单的纯文本邮件 4、邮件发送问题 5、使用 JavaMail 接收邮件 6、使用 JavaMail 发送图片、附件邮件 1、JavaMail 介绍 JavaMail 是sun公司(现以被甲骨文收购)为方便Java开发人员在应用程序中实现邮件发送和接收功能而提供的一套标准开发包,它支持一些常用的邮件协议,如前面所讲的SMTP,POP3,IMAP,还有MIME等。我们在使用JavaMail API

weixin_39710170的博客 932

【java】javamail发送附件邮件

一、前言      很多我们都使用过邮件,通过邮件附件发送一些东西,达到传送的目的,这个目的还是不错的。但是各位知道我们是如何添加附件呢?如何通过代码完成的呢?二、附件是什么?      我们发送邮件除了邮件的主题内容,可以添加一些其他类型的文件,发送过出去。这些文件可以是图片、文档、视频等。很像是在我们写信一样把信写好后放进信封,同样我们也可以在信封中放一些其他的东西,比如钥匙,钱等。附件就等

哈士奇 6698

javamail邮件发送附件发送

package com.frame.util; import java.util.Date; import java.util.Enumeration; import java.util.Properties; import java.util.Vector; import javax.activation.*; import javax.mail.Authenticator; import

技术之家 www.5ceo.cn 1805

java发送附件的qq邮箱,JavaMail邮件发送-能发送附件背景音乐的邮件的小系统...

原标题:JavaMail邮件发送-能发送附件背景音乐的邮件的小系统这里使用的是JavaMail技术,前台使用了fckeditor做邮件美化,由于只是示例,后台发送时只是将邮件保存在本地,但是可以查看,如果需要实际发送,请参考我的其他博客文章,我写了很多关于邮件发送的示例!JSP页面页面除了引用fckeditor外,要注意我们是需要发送附件的: 为了防止乱码,会经过一个过滤器: 然后到Ser...

weixin_35706281的博客 742

java中javamail发送附件邮件实现方法

/设置信件头的发送日期。//用于保存发送附件的文件名的集合。存在的问题就是发送到163的邮件全部都有一个附件的符号,不管有没有发送附件,感兴趣的朋友可以对此加以改进和完善。//System.out.println("\n提示信息:"+message);//定义发件人、收件人、SMTP服务器、用户名、密码、主题、内容等。file.isEmpty()){//有附件

weixin_19970108018的博客 2215
上一篇: 用VC调整显示器的分辨率
下一篇: CListCtrl使用详解
fairness
博客等级 码龄23年 6粉丝 8原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值