您可以使用电子邮件服务来处理 入站电子邮件。例如,您可以创建自动创建的电子邮件服务 基于邮件中的联系人信息的联系人记录。您可以将每个电子邮件服务与一个或多个 Salesforce 生成的电子邮件相关联 用户可以向其发送消息进行处理的地址。授予多个用户访问权限 对于单个电子邮件服务,您可以:
- 关联多个 Salesforce 生成的电子邮件地址与电子邮件服务并分配 这些地址给用户。
- 关联单个 Salesforce 生成的 电子邮件地址,并编写一个执行 根据访问电子邮件服务的用户。例如,您可以 编写一个 Apex 类,该类根据用户的电子邮件地址标识用户 并代表该用户创建记录。
要使用电子邮件服务,请从“设置”中输入“快速查找”框,然后选择“电子邮件” 服务。
Email Services
- 单击“新建电子邮件服务”以定义新电子邮件 服务。
- 选择现有电子邮件服务以查看其配置,激活或 停用它,然后查看或指定该电子邮件服务的地址。
- 单击“编辑”以对现有电子邮件进行更改 服务。
- 单击“删除”以删除电子邮件服务。注意以前 删除电子邮件服务,您必须删除所有关联的电子邮件服务 地址。
什么时候 定义电子邮件服务时,请注意以下几点:
- 电子邮件服务仅处理在其 地址。
- Salesforce 限制 所有电子邮件服务(包括按需电子邮件到案例)都可以处理 日常。超过此限制的邮件将被退回、丢弃或排队等待 第二天处理,具体取决于您如何为每个电子邮件服务配置失败响应设置。Salesforce 通过将 用户许可证数量增加 1,000 个;最大 1,000,000。例如,如果您有 10 个许可证,您的组织最多可以处理 10,000 封电子邮件 日。
- 您在沙盒中创建的电子邮件服务地址无法复制到 生产组织。
- 对于每个电子邮件服务,您可以告诉 Salesforce 将错误电子邮件发送到 指定的地址,而不是发件人的电子邮件地址。
- 电子邮件服务拒绝电子邮件并通知发件人 如果电子邮件(正文文本、正文 HTML 和附件组合)超过 大约25兆字节 (因语言和性格而异 设置).
使用 InboundEmail 对象
对于 Apex 电子邮件服务域收到的每封电子邮件,Salesforce 都会创建一个单独的 包含该电子邮件的内容和附件的 InboundEmail 对象。你可以使用 实现接口以处理入站电子邮件的 Apex 类。 使用该类中的方法, 您可以访问 InboundEmail 对象来检索 入站电子邮件,以及执行许多功能。
Messaging.InboundEmailHandlerhandleInboundEmail
示例 1:为联系人创建任务
以下示例说明了如何根据入站查找联系人 电子邮件地址并创建一个新任务。
public with sharing class CreateTaskEmailExample implements Messaging.InboundEmailHandler {
public Messaging.InboundEmailResult handleInboundEmail(Messaging.inboundEmail email,
Messaging.InboundEnvelope env){
// Create an InboundEmailResult object for returning the result of the
// Apex Email Service
Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
String myPlainText= '';
// Add the email plain text into the local variable
myPlainText = email.plainTextBody;
// New Task object to be created
Task[] newTask = new Task[0];
// Try to look up any contacts based on the email from address
// If there is more than one contact with the same email address,
// an exception will be thrown and the catch statement will be called.
try {
Contact vCon = [SELECT Id, Name, Email
FROM Contact
WHERE Email = :email.fromAddress
WITH USER_MODE
LIMIT 1];
// Add a new Task to the contact record we just found above.
newTask.add(new Task(Description = myPlainText,
Priority = 'Normal',
Status = 'Inbound Email',
Subject = email.subject,
IsReminderSet = true,
ReminderDateTime = System.now()+1,
WhoId = vCon.Id));
// Insert the new Task
insert as user newTask;
System.debug('New Task Object: ' + newTask );
}
// If an exception occurs when the query accesses
// the contact record, a QueryException is called.
// The exception is written to the Apex debug log.
catch (QueryException e) {
System.debug('Query Issue: ' + e);
}
// Set the result to true. No need to send an email back to the user
// with an error message
result.success = true;
// Return the result for the Apex Email Service
return result;
}
}
示例 2:处理退订电子邮件
向客户和潜在客户发送营销电子邮件的公司必须提供 让收件人退订的方式。以下是电子邮件如何 服务可以处理退订请求。该代码搜索 “取消订阅”一词的入站电子邮件。如果找到该单词,则 代码查找与发件人电子邮件地址匹配的所有联系人和潜在顾客,并将电子邮件选择退出字段 () 设置为 True。HasOptedOutOfEmail
public with sharing class unsubscribe implements Messaging.inboundEmailHandler{
public Messaging.InboundEmailResult handleInboundEmail(Messaging.InboundEmail email,
Messaging.InboundEnvelope env ) {
// Create an inboundEmailResult object for returning
// the result of the email service.
Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
// Create contact and lead lists to hold all the updated records.
List<Contact> lc = new List <contact>();
List<Lead> ll = new List <lead>();
// Convert the subject line to lower case so the program can match on lower case.
String mySubject = email.subject.toLowerCase();
// The search string used in the subject line.
String s = 'unsubscribe';
// Check the variable to see if the word "unsubscribe" was found in the subject line.
Boolean unsubMe;
// Look for the word "unsubcribe" in the subject line.
// If it is found, return true; otherwise, return false.
unsubMe = mySubject.contains(s);
// If unsubscribe is found in the subject line, enter the IF statement.
if (unsubMe == true) {
try {
// Look up all contacts with a matching email address.
for (Contact c : [SELECT Id, Name, Email, HasOptedOutOfEmail
FROM Contact
WHERE Email = :env.fromAddress
AND hasOptedOutOfEmail = false
WITH USER_MODE
LIMIT 100]) {
// Add all the matching contacts into the list.
c.hasOptedOutOfEmail = true;
lc.add(c);
}
// Update all of the contact records.
update as user lc;
}
catch (System.QueryException e) {
System.debug('Contact Query Issue: ' + e);
}
try {
// Look up all leads matching the email address.
for (Lead l : [SELECT Id, Name, Email, HasOptedOutOfEmail
FROM Lead
WHERE Email = :env.fromAddress
AND isConverted = false
AND hasOptedOutOfEmail = false
WITH USER_MODE
LIMIT 100]) {
// Add all the leads to the list.
l.hasOptedOutOfEmail = true;
ll.add(l);
System.debug('Lead Object: ' + l);
}
// Update all lead records in the query.
update as user ll;
}
catch (System.QueryException e) {
System.debug('Lead Query Issue: ' + e);
}
System.debug('Found the unsubscribe word in the subject line.');
}
else {
System.debug('No Unsuscribe word found in the subject line.' );
}
// Return True and exit.
// True confirms program is complete and no emails
// should be sent to the sender of the unsubscribe request.
result.success = true;
return result;
}
}
@isTest
private class unsubscribeTest {
// The following test methods provide adequate code coverage
// for the unsubscribe email class.
// There are two methods, one that does the testing
// with a valid "unsubcribe" in the subject line
// and one the does not contain "unsubscribe" in the
// subject line.
static testMethod void testUnsubscribe() {
// Create a new email and envelope object.
Messaging.InboundEmail email = new Messaging.InboundEmail() ;
Messaging.InboundEnvelope env = new Messaging.InboundEnvelope();
// Create a new test lead and insert it in the test method.
Lead l = new lead(firstName='John',
lastName='Smith',
Company='Salesforce',
Email='user@acme.com',
HasOptedOutOfEmail=false);
insert l;
// Create a new test contact and insert it in the test method.
Contact c = new Contact(firstName='john',
lastName='smith',
Email='user@acme.com',
HasOptedOutOfEmail=false);
insert c;
// Test with the subject that matches the unsubscribe statement.
email.subject = 'test unsubscribe test';
env.fromAddress = 'user@acme.com';
// Call the class and test it with the data in the testMethod.
unsubscribe unsubscribeObj = new unsubscribe();
unsubscribeObj.handleInboundEmail(email, env );
}
static testMethod void testUnsubscribe2() {
// Create a new email and envelope object.
Messaging.InboundEmail email = new Messaging.InboundEmail();
Messaging.InboundEnvelope env = new Messaging.InboundEnvelope();
// Create a new test lead and insert it in the test method.
Lead l = new lead(firstName='john',
lastName='smith',
Company='Salesforce',
Email='user@acme.com',
HasOptedOutOfEmail=false);
insert l;
// Create a new test contact and insert it in the test method.
Contact c = new Contact(firstName='john',
lastName='smith',
Email='user@acme.com',
HasOptedOutOfEmail=false);
insert c;
// Test with a subject that does not contain "unsubscribe."
email.subject = 'test';
env.fromAddress = 'user@acme.com';
// Call the class and test it with the data in the test method.
unsubscribe unsubscribeObj = new unsubscribe();
unsubscribeObj.handleInboundEmail(email, env );
// Assert that the Lead and Contact have been unsubscribed
Lead updatedLead = [Select Id, HasOptedOutOfEmail from Lead where Id = :l.Id];
Contact updatedContact = [Select Id, HasOptedOutOfEmail from Contact where Id = :c.Id];
Assert.isTrue(l.HasOptedOutOfEmail);
Assert.isTrue(c.HasOptedOutOfEmail);
}
}
Visualforce 类
除了使开发人员能够向 Salesforce 添加业务逻辑之外 系统事件,例如按钮点击和相关记录更新,Apex 也可用于 通过自定义 Visualforce 控制器为 Visualforce 页面提供自定义逻辑,以及 控制器扩展。
- 自定义控制器是用 Apex 编写的类,它实现了页面的所有 逻辑,而无需使用标准控制器。如果您使用自定义控制器,则 可以定义新的导航元素或行为,但还必须重新实现任何 标准控制器中已提供的功能。像其他 Apex 一样 类,自定义控制器完全在系统模式下执行,其中对象 并且忽略当前用户的字段级权限。您可以指定 用户是否可以根据用户的 轮廓。
- 控制器扩展是用 Apex 编写的类,用于添加或覆盖行为 在标准或自定义控制器中。扩展允许您利用 另一个控制器的功能,同时添加您自己的自定义逻辑。因为 标准控制器在用户模式下执行,其中权限为字段级 安全性,并强制执行当前用户的共享规则,从而扩展了 标准控制器允许您构建尊重用户的 Visualforce 页面 权限。尽管扩展类在系统模式下执行,但标准 控制器在用户模式下执行。与自定义控制器一样,您可以指定 用户是否可以根据用户的 轮廓。
在构建自定义 Visualforce 时,可以使用这些系统提供的 Apex 类 控制器和控制器扩展。
- 行动
- 动态组件
- IdeaStandardController(理念标准控制器)
- IdeaStandardSet控制器
- KnowledgeArticleVersionStandardController
- 消息
- 页面参考
- 选择选项
- 标准控制器
- 标准集控制器
除了这些类之外,在控制器和控制器扩展中声明方法时还可以使用关键字。为 更多信息,请参阅使用 瞬态关键字。transient
有关 Visualforce 的更多信息,请参阅 Visualforce 开发人员的 指南。
JavaScript 远程处理
在 Visualforce 中使用 JavaScript 远程处理从 JavaScript的。创建具有复杂动态行为的页面,这是 标准 Visualforce AJAX 组件。使用 JavaScript 远程处理实现的功能需要三个元素:
- 您添加到 Visualforce 页面的远程方法调用,写在 JavaScript的。
- Apex 控制器类中的远程方法定义。此方法 定义是用 Apex 编写的,但与 正常操作方法。
- 您添加到或包含在 Visualforce 中的响应处理程序回调函数 页面,用 JavaScript 编写。
在控制器中,Apex 方法声明前面带有类似 这:
@RemoteAction
@RemoteAction
global static String getItemId(String objectName) { ... }
Apex 方法必须是 和 或 。
@RemoteActionstaticglobalpublic将 Apex 类作为自定义控制器或控制器扩展添加到 页。
<apex:page controller="MyController" extension="MyExtension">
警告
添加控制器或控制器扩展将授予对该 Apex 类中所有方法的访问权限, 即使页面中未使用这些方法。任何可以查看该页面的人都可以 执行所有方法并提供 向控制器发送虚假或恶意数据。@RemoteAction@RemoteAction然后,将请求添加为 JavaScript 函数调用。一个简单的 JavaScript 远程调用需要以下操作 形式。
[namespace.]MyController.method(
[parameters...,]
callbackFunction,
[configuration]
);
元素 | 描述 |
---|---|
namespace | 控制器类的命名空间。namespace 元素是 如果您的组织定义了命名空间,或者如果 类来自已安装的包。 |
MyController,MyExtension | Apex 控制器或扩展的名称。 |
method | 要调用的 Apex 方法的名称。 |
parameters | 方法的参数的逗号分隔列表 需要。 |
callbackFunction | 处理响应的 JavaScript 函数的名称 从控制器。您还可以声明匿名函数 内嵌。 接收方法调用的状态和结果 参数。callbackFunction |
configuration | 配置远程呼叫和响应的处理。使用这个 元素来更改远程处理调用的行为,例如是否 或者不转义 Apex 方法的响应。 |
有关更多信息,请参阅《Visualforce 开发人员指南》中的适用于 Apex 控制器的 JavaScript 远程处理。
AJAX 中的 Apex
AJAX 工具包包括对通过匿名块调用 Apex 的内置支持 或公共方法。
webservice
要通过匿名块或公共方法调用 Apex,请在 AJAX 代码中包含以下行:webservice
<script src="/soap/ajax/59.0/connection.js" type="text/javascript"></script>
<script src="/soap/ajax/59.0/apex.js" type="text/javascript"></script>
注意
对于 AJAX 按钮,请使用这些包含的替代形式。若要调用 Apex,请使用以下两种方法之一:
- 通过匿名执行。这 方法返回的结果类似于 API 的结果类型,但作为 JavaScript 结构。sforce.apex.executeAnonymous (script)
- 使用类 WSDL。例如,您可以调用以下 Apex 类:
global class myClass { webservice static Id makeContact(String lastName, Account a) { Contact c = new Contact(LastName = lastName, AccountId = a.Id); return c.id; } }
通过使用以下 JavaScript 法典:var account = sforce.sObject("Account"); var id = sforce.apex.execute("myClass","makeContact", {lastName:"Smith", a:account});
该方法采用原始数据 类型、sObject 和基元或 sObject 列表。execute要调用 不带参数的 webservice 方法,用作 的第三个参数。例如,调用以下 Apex 类:{}sforce.apex.executeglobal class myClass{ webservice static String getContextUserName() { return UserInfo.getFirstName(); } }
使用以下 JavaScript 法典:var contextUser = sforce.apex.execute("myClass", "getContextUserName", {});
注意如果已为您的 组织,则在调用 类。例如,要调用类, 上面的 JavaScript 代码将被重写为 遵循:myClassvar contextUser = sforce.apex.execute("myNamespace.myClass", "getContextUserName", {});
若要验证组织是否具有命名空间,请记录 在您的 Salesforce 组织中,然后从“设置”中输入“快速” “查找”框,然后选择“包”。如果 命名空间已定义,它列在“开发人员”下 设置。Packages有关返回数据类型的详细信息,请参阅 AJAX 中的数据类型 工具箱
使用以下行显示包含调试信息的窗口:
sforce.debug.trace=true;