-->

2026年5月18日月曜日

alfresco26.x メール取り込み設定(スパム対策あり)

1. システム構成の概要

メールサーバーから自動受信したメールをSpamAssassinでフィルタリングし、Alfrescoに取り込む構成です。

📬 メールサーバー (POP3S)
getmail
spamc-wrapper.sh
SpamAssassin
postfix
🗂 Alfresco
コンポーネント役割備考
getmail 6.xPOP3S でメール取得cron で5分毎に実行
SpamAssassin 4.0スパム判定・件名に ***SPAM*** 追加スコア10以上は破棄
postfix 3.8Alfresco への配送・遅延制御5秒/通の遅延設定
Alfresco 26.1メール格納・振り分けCommunity版 Ansible インストール
ℹ️ Alfresco Community版はSMTPの細かい制御ができないため、postfixで遅延処理を行い配送エラーを防止しています。

2. Alfresco 事前設定(alfresco-global.properties)

Alfresco のメール受信機能を有効にするため、設定ファイルにメール関連プロパティを追加します。

① サンプルファイルから設定を確認

サンプルファイルからメール関連の設定を参照します。

terminal
$ vi /etc/opt/alfresco/content-services/classpath/alfresco-global.properties.sample

サンプルファイル内のメール関連の記述(抜粋):

alfresco-global.properties.sample(抜粋)
# Alfresco Email Service and Email Server
#-------------
# Enable/Disable the inbound email service.
#-------------
#email.inbound.enabled=true
 
# Email Server properties
#-------------
#email.server.enabled=true
#email.server.port=25
#email.server.domain=alfresco.com
#email.inbound.unknownUser=anonymous

② alfresco-global.properties に追記

上記サンプルを参考に、実際の設定ファイルへ追記します。

terminal
$ sudo vi /etc/opt/alfresco/content-services/classpath/alfresco-global.properties

ファイル末尾の ### Begin - Custom user properties - ANSIBLE MANAGED BLOCK セクションに以下を追記します。

alfresco-global.properties(追記内容)
# Enable/Disable the inbound email service.
#-------------
email.inbound.enabled=true  # メール受信を行う
 
# Email Server properties
#-------------
email.server.enabled=true  # SMTPサーバを起動する
email.server.port=1025  # 受信ポートを指定(25はpostfix等のMTAと干渉するため変更)
email.server.domain=alfresco.example.com  # ドメインを指定
email.inbound.unknownUser=admin  # 受信ユーザーを指定(後の設定上、上位権限をもつユーザーを指定)
⚠️ email.server.port=25 はpostfixなどのMTAが使用しているため、1025など別のポートに変更してください。postfix の relayhost に指定するポートと一致させます。
ℹ️ email.inbound.unknownUser=admin は、送信者がAlfrescoのユーザーとして登録されていない場合に使用するユーザーです。後述のルール設定でフォルダへの書き込み権限が必要なため、管理者権限を持つユーザーを指定します。

③ Alfrescoサービスを再起動

terminal
$ sudo systemctl restart alfresco-content.service

3. Postfix のインストールと設定

Ubuntu 24.04 に postfix をインストールし、Alfresco への遅延配送を設定します。

インストール

terminal
$ sudo apt install postfix -y
$ sudo systemctl enable --now postfix

/etc/postfix/main.cf の設定

/etc/postfix/main.cf
myhostname = alfresco.example.com
mydomain = example.com
inet_interfaces = localhost
relayhost = [alfresco.example.com]:1025
 
# メールの最大サイズ
message_size_limit = 40960000
 
# 配送遅延(Alfrescoの処理速度に合わせて調整)
smtp_destination_rate_delay = 5s
smtp_destination_concurrency_limit = 1
⚠️ 遅延設定なしでスクリプトが設定されたフォルダに配送すると、処理しきれず配送エラーや0byteファイルが発生します。

4. getmail のインストールと設定

インストール

terminal
$ sudo apt install getmail6 -y && mkdir -m 0700 ~/.getmail

~/.getmail/getmailrc の設定

~/.getmail/getmailrc
[options]
read_all = false
max_messages_per_session = 10
 
[retriever]
type = SimplePOP3SSLRetriever
server = mail.example.com
username = info@example.com
password = xxxxxxxx
 
[destination]
type = MDA_external
path = /usr/local/bin/spamc-wrapper.sh
arguments = ("%(sender)",)
ℹ️ %(sender) を引数として渡すことで、SpamAssassin処理後も送信者アドレスが正しくpostfixに渡されます。

cron 設定(5分毎)

crontab -e
# 標準エラーの出力を無効化しないと配送エラーとなるため /dev/null 2>&1 を追加
*/5 * * * * /usr/bin/getmail >> /var/log/getmail.log 2>&1

5. SpamAssassin の導入

インストール

terminal
$ sudo apt install spamassassin spamc -y
$ sudo systemctl enable --now spamd

/etc/default/spamd の設定

Ubuntu 24.04 では /etc/default/spamdOPTIONS--siteconfigpath を追加しないと、local.cf のブラックリスト設定が spamd に読み込まれません。

⚠️ この設定がないと spamassassin -t ではブラックリストが有効でも、spamc 経由では無効になります。必ず設定してください。
terminal
$ sudo vi /etc/default/spamd
/etc/default/spamd(OPTIONS行を変更)
# 変更前
OPTIONS="--create-prefs --max-children 5 --helper-home-dir"
 
# 変更後(--siteconfigpath を追加)
OPTIONS="--create-prefs --max-children 5 --helper-home-dir --siteconfigpath /etc/spamassassin"
terminal(設定反映)
$ sudo systemctl restart spamd

/etc/spamassassin/local.cf の設定

/etc/spamassassin/local.cf
# スパム判定閾値
required_score 5.0
 
# 日本語対応
ok_locales ja
ok_languages ja en
 
# 件名に ***SPAM*** を追加
rewrite_header Subject ***SPAM***
 
# ブラックリスト(スパム送信元ドメイン)
# 国別ドメイン(スパム送信元として多いもの)
blacklist_from *@*.cn
blacklist_from *@*.su
# スパム送信元として確認されたドメイン(受信ログから追加)
blacklist_from *@スパムドメイン1.*
blacklist_from *@スパムドメイン2.*
# バウンスメール・なりすましを防止
blacklist_from MAILER-DAEMON@*
 
# ホワイトリスト(信頼するドメイン・誤判定を防ぐ)
# 自組織のドメイン
whitelist_from *@example.com
# 信頼できる取引先・外部サービス
whitelist_from *@信頼ドメイン1.co.jp
whitelist_from *@信頼ドメイン2.co.jp
# キャリアメール(携帯・スマートフォン)
whitelist_from *@docomo.ne.jp
whitelist_from *@softbank.ne.jp
whitelist_from *@au.com

設定反映・動作確認

terminal
$ sudo sa-update && sudo systemctl restart spamd
$ # ブラックリストの動作確認(スコアが高ければ正常)
$ echo "From: test@spam.cn" | spamc -f | grep "X-Spam-Status"
スコア対応
5.0 以上スパム判定(件名に ***SPAM*** 追加)
7.0 以上破棄(Alfresco に配送しない)
5.0 未満正常メール(Alfresco へ配送)
ℹ️ 破棄スコアの閾値は spamc-wrapper.shSCORE_INT -ge 7 で設定しています。環境に合わせて調整してください。

6. spamc-wrapper スクリプト

getmail から呼び出され、SpamAssassin でフィルタリング後に postfix 経由で Alfresco へ配送します。

⚠️ postfix の content_filter = spamassassin を設定するとメールループが発生します。必ずコメントアウトし、getmailrc からラッパースクリプトを直接呼び出す方式を採用してください。

破棄条件

条件内容
MAILER-DAEMONバウンスメールを破棄
スコア 7 以上ローカルSpamAssassinのスコアが7以上
X-Spam-Flag: YESローカル・メールサーバー側問わずスパムフラグあり
件名に SPAM 含むSubject・X-Spam-Prev-Subject に SPAM が含まれる
/usr/local/bin/spamc-wrapper.sh
#!/bin/bash
echo "sender: $1" >> /tmp/spamc-wrapper.log
 
# MAILER-DAEMON は破棄
if [[ "$1" == *"MAILER-DAEMON"* ]] || [[ "$1" == "" ]]; then
  echo "DISCARDED: MAILER-DAEMON" >> /tmp/spamc-wrapper.log
  exit 0
fi
 
TMPFILE=$(mktemp)
/usr/bin/spamc -f > "$TMPFILE"
 
# スコアの最大値を取得(ローカル・サーバー側両方)
SPAM_FLAG=$(grep "X-Spam-Flag:" "$TMPFILE" | head -1 | awk '{print $2}')
SPAM_SCORE=$(grep "X-Spam-Status:" "$TMPFILE" | grep -oP 'score=\K[0-9.]+' | sort -rn | head -1)
echo "flag: $SPAM_FLAG score: $SPAM_SCORE" >> /tmp/spamc-wrapper.log
 
# スコア7以上は破棄
if [ -n "$SPAM_SCORE" ]; then
  SCORE_INT=$(echo "$SPAM_SCORE" | cut -d. -f1)
  if [ "$SCORE_INT" -ge 7 ]; then
    echo "DISCARDED(score): $1 score=$SPAM_SCORE" >> /tmp/spamc-wrapper.log
    rm -f "$TMPFILE"
    exit 0
  fi
fi
 
# X-Spam-Flag: YES(ローカル・サーバー問わず)は破棄
if grep -qi "^X-Spam-Flag: YES" "$TMPFILE"; then
  echo "DISCARDED(flag-yes): $1" >> /tmp/spamc-wrapper.log
  rm -f "$TMPFILE"
  exit 0
fi
 
# 件名・X-Spam-Prev-SubjectにSPAMが含まれる場合も破棄
if grep -i "^Subject:\|^X-Spam-Prev-Subject:" "$TMPFILE" | grep -qi "SPAM"; then
  echo "DISCARDED(subject): $1" >> /tmp/spamc-wrapper.log
  rm -f "$TMPFILE"
  exit 0
fi
 
# Alfrescoへ配送
/usr/sbin/sendmail -oi -f "$1" mail@alfresco.example.com < "$TMPFILE"
rm -f "$TMPFILE"
terminal
$ sudo chmod +x /usr/local/bin/spamc-wrapper.sh
ℹ️ 破棄されたメールは /tmp/spamc-wrapper.logDISCARDED(score)DISCARDED(flag-yes)DISCARDED(subject) として記録されます。定期的に確認して誤判定がないか確認してください。

7. Alfresco スクリプト群

メール格納フォルダのルールに登録するJavaScriptスクリプトです。
リポジトリ > Data Dictionary > Scripts に登録し、メール格納フォルダのルールに設定します。
sortAdd.js のみ各振り分け先フォルダのルールに設定します。

スクリプト役割実行設定
mailRename.js件名に送信日時を付加・URLエンコード文字を全角に置換通常実行
mailFolderCreate.jsメール本体受信時にフォルダを作成・アスペクト付与通常実行
mailFolderMove.jsメールをフォルダへ移動バックグラウンド実行
mailSort.js送信者アドレスで振り分け・スパムは「spam」フォルダへ通常実行
mailSortAdd.js手動振り分け時に送信者アドレスを登録各振り分けフォルダのルール
⚠️ mailFolderMove.js のみ「バックグラウンドで実行」にチェックが必要です。move API はバックグラウンド実行が必要なため、別スクリプトに分離しています。

mailRename.js — ファイル名に送信日時を追加

同名メールの重複を防ぐため送信日時を付加し、URLエンコードされた記号を全角に置換します。
拡張子を判定して正しいMIMEタイプを設定します。PDF・Excel・Word等の添付ファイルがHTMLと誤判定されるのを防ぎます。

ℹ️ メール取り込み時、添付ファイル(PDF・Excel・Word等)のMIMEタイプが text/html に誤設定される問題があります。拡張子を先にチェックして正しいMIMEタイプを設定することで解決します。
mailRename.js
// 送信日時・作成日時を取得
var mailDate = document.properties['cm:sentdate'];
var creatDate = document.properties['cm:created'];
if (mailDate != null && document.isDocument) {
  var year_str = ('0' + mailDate.getFullYear()).slice(-2);
  var month_str = ('0' + (1 + mailDate.getMonth())).slice(-2);
  var day_str = ('0' + mailDate.getDate()).slice(-2);
  var hour_str = ('0' + mailDate.getHours()).slice(-2);
  var minute_str = ('0' + mailDate.getMinutes()).slice(-2);
  var second_str = ('0' + mailDate.getSeconds()).slice(-2);
  var Csecond_str = ('0' + creatDate.getSeconds()).slice(-1);
  var format_str = 'YYMMDDhhmmssz'
    .replace(/YY/g, year_str).replace(/MM/g, month_str)
    .replace(/DD/g, day_str).replace(/hh/g, hour_str)
    .replace(/mm/g, minute_str).replace(/ss/g, second_str)
    .replace(/z/g, Csecond_str);
  var stringDate = format_str + '_';
} else {
  var stringDate = '';
}
 
// ========MIMEタイプを拡張子で判定・修正=========
var fullName = document.properties['cm:name'];
var lowerName = new String(fullName).toLowerCase();
var dotPos = lowerName.lastIndexOf('.');
var ext = (dotPos >= 0) ? lowerName.substring(dotPos + 1) : '';
 
if (ext === 'pdf') {
  document.mimetype = 'application/pdf';
} else if (ext === 'xlsx') {
  document.mimetype = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
} else if (ext === 'xls') {
  document.mimetype = 'application/vnd.ms-excel';
} else if (ext === 'docx') {
  document.mimetype = 'application/vnd.openxmlformats-officedocument.wordprocessingml.document';
} else if (ext === 'doc') {
  document.mimetype = 'application/msword';
} else if (ext === 'pptx') {
  document.mimetype = 'application/vnd.openxmlformats-officedocument.presentationml.presentation';
} else if (ext === 'ppt') {
  document.mimetype = 'application/vnd.ms-powerpoint';
} else if (ext === 'csv') {
  document.mimetype = 'text/csv';
} else if (ext === 'zip') {
  document.mimetype = 'application/zip';
} else {
  // 上記以外:HTMLタグが5回以上出現した場合html文書と判断
  var mailContent = document.content;
  if ((mailContent.match(/(<([^>]+)>)/gi) || []).length > 5) {
    document.mimetype = 'text/html';
  }
}
// ========ここまで=========
 
// URLエンコード文字を全角に置換
var replaced = fullName
  .replace(/%3a/g,':').replace(/%2f/g,'/').replace(/%3f/g,'?')
  .replace(/%7c/g,'|').replace(/%22/g,'"').replace(/%2a/g,'*')
  .replace(/%3c/g,'<').replace(/%3e/g,'>');
document.properties['cm:name'] = stringDate + replaced;
document.save();
拡張子設定されるMIMEタイプ
pdfapplication/pdf
xlsxapplication/vnd.openxmlformats-officedocument.spreadsheetml.sheet
xlsapplication/vnd.ms-excel
docxapplication/vnd.openxmlformats-officedocument.wordprocessingml.document
docapplication/msword
pptxapplication/vnd.openxmlformats-officedocument.presentationml.presentation
pptapplication/vnd.ms-powerpoint
csvtext/csv
zipapplication/zip
上記以外HTMLタグ数で判定(5回以上でtext/html)
⚠️ 既存の取り込み済みファイルのMIMEタイプを修正するには、別途 fixMime.js スクリプトをData Dictionary/Scriptsに登録し、REST API経由で実行します。

mailFolderCreate.js — メールフォルダ作成

メール本体(送信者情報あり)受信時にフォルダを作成し、発行日・送信者アスペクトを付与します。次のメールまでフォルダのノードを cs:address に一時保存します。

mailFolderCreate.js
// メール格納フォルダのノードを取得
var parentNode = companyhome.childByNamePath('Shared/mail');
var mailFrom = document.properties['cm:originator'];
if (mailFrom != null) {
  var fullName = document.properties['cm:name'];
  var fileName = fullName.split('.')[0];
  var titleFolder = space.childByNamePath(fileName);
  if (fullName.indexOf('.') == -1 && titleFolder.isDocument
    || titleFolder == null && space.hasPermission('CreateChildren')) {
    // フォルダ名重複を避けるため⁑を付加
    titleFolder = space.createFolder('⁑' + fileName);
    // フォルダの説明に本文冒頭60文字を追加
    var mailContent = new String(document.content)
      .replace(/\r?\n/g,' ')
      .replace(/[^0-9A-Za-z\u3041-\u9fff\uFF10-\uFF9F]/g, '');
    titleFolder.properties['cm:description'] = mailContent.slice(0,60);
    titleFolder.save();
    // 送信日時・送信者アスペクトを追加
    var props = new Array(2);
    props['cm:sentdate'] = document.properties['cm:sentdate'];
    props['cm:originator'] = mailFrom;
    titleFolder.addAspect('cm:emailed', props);
    // 発行日アスペクトを追加(ソート用)
    var CSprops = new Array(1);
    CSprops['cs:publishdate'] = document.properties['cm:sentdate'];
    titleFolder.addAspect('cs:published', CSprops);
  }
  // 作成フォルダのノードを一時保存
  parentNode.properties['cs:address'] = titleFolder;
  parentNode.save();
}

mailFolderMove.js — メールをフォルダへ移動(バックグラウンド実行)

一時保存されたフォルダのノードへメールを移動します。発行日アスペクトを付与して送信者・送信日時も引き継ぎます。

mailFolderMove.js
// メール格納フォルダのノードを取得
var parentNode = companyhome.childByNamePath('Shared/mail');
// 一時保存されたフォルダのノード文字列を取得
var nodeString = parentNode.properties['cs:address'];
var convNode = search.findNode(nodeString);
 
// 発行日アスペクトを追加し送信者・送信日時を引き継ぎ
var props = new Array(2);
props['cs:publishdate'] = convNode.properties['cm:sentdate'];
props['cs:publisher'] = convNode.properties['cm:originator'];
document.addAspect('cs:published', props);
 
// 格納フォルダへ移動
document.move(convNode);
ℹ️ move.js のみ「バックグラウンドで実行」にチェックが必要です。move API はバックグラウンド実行が必要なため、別スクリプトに分離しています。

mailSort.js(振り分けスクリプト v1.4)

件名に SPAM を含むメールは最優先で spam フォルダへ、自組織ドメインのメールは別サイトの提出箱フォルダへ直接移動します。それ以外は各振り分けフォルダの cs:address に登録されたアドレスと照合して移動します。

優先順位条件移動先
件名に SPAM を含むspam フォルダ(sa-learn学習用)
送信元が自組織ドメイン(@example.com別サイトの提出箱フォルダへ直接移動
cs:address に登録済みのアドレス各振り分けフォルダ
-いずれにも該当しない移動なし(mail フォルダに残る)
ℹ️ 振り分けフォルダ名は任意に設定できます。下記は汎用的な例です。getAdd('フォルダ名') を追加・削除して用途に合わせてカスタマイズしてください。
mailSort.js
// ① SPAMは「spam」フォルダへ(sa-learn学習用)
var fileName = document.properties['cm:name'];
if (fileName.indexOf("SPAM") != -1) {
  var dest = document.parent.childByNamePath('spam');
  document.move(dest);
}
else {
  var mailFrom = document.properties['cm:originator'];
  if (mailFrom != null) {
 
    // ② 自組織ドメインは提出箱へ直接移動(その他経由なし)
    if (new String(mailFrom).toLowerCase().indexOf('@example.com') != -1) {
      var teishutsu = search.findNode(
        'workspace://SpacesStore/提出箱フォルダのノードID');
      if (teishutsu != null) { document.move(teishutsu); }
    }
    // ③ それ以外はcs:addressで振り分け先判定
    else {
      function getAdd(sortFolder) {
        dest = document.parent.childByNamePath(sortFolder);
        if (dest == null) return new RegExp('(?!)');
        var adList = dest.properties['cs:address'];
        if (adList == null) return new RegExp('(?!)');
        var adListStr = new String(adList).trim();
        if (adListStr === '' || adListStr === 'null') return new RegExp('(?!)');
        return new RegExp(adListStr.replace(/\r?\n/g, '|'));
      }
      if (getAdd('フォルダA').test(mailFrom)) { document.move(dest); }
      else if (getAdd('フォルダB').test(mailFrom)) { document.move(dest); }
      else if (getAdd('フォルダC').test(mailFrom)) { document.move(dest); }
      else if (getAdd('その他').test(mailFrom)) { document.move(dest); }
      // 必要に応じて else if を追加
    }
  }
}
ℹ️ cs:address の容量上限に注意
各振り分けフォルダの cs:address プロパティは最大50,000文字(d:text型)です。特に「その他」フォルダは多数のアドレスが蓄積されやすく、上限に達するとルール実行時にエラーが大量ループし、サーバー全体の負荷が急増する原因になります。定期的にアドレスリストを整理することを推奨します。

mailSortAdd.js(アドレス登録スクリプト)

mailSortAdd.js
// 作成日を取得
var created = document.properties['cm:created'];
// 変更日を取得
var modified = document.properties['cm:modified'];
 
// 作成日と変更日が異なる=手動移動の場合スクリプトを続行
if (created != modified) {
  var mailFrom = document.properties['cm:originator'];
  if (mailFrom == null) {
    // 送信者情報がない場合はスキップ
  } else {
    var parentNode = document.parent;
    var adList = parentNode.properties['cs:address'];
    // cs:address が null または空の場合は直接追加
    if (adList == null
      || new String(adList).trim() === ''
      || new String(adList).trim() === 'null') {
      parentNode.properties['cs:address'] = mailFrom;
      parentNode.save();
    } else {
      var adListStr = new String(adList);
      var regexp = new RegExp(adListStr.replace(/\r?\n/g, '|'));
      // アドレスリストに含まれていない場合のみ追加
      if (!regexp.test(mailFrom)) {
        parentNode.properties['cs:address'] = adListStr + '\n' + mailFrom;
        parentNode.save();
      }
    }
  }
}

8. カスタムモデルの設定

モデルマネージャーで作成したカスタムモデルの構成です。

アスペクト名プロパティ用途
cs:publishedcs:publishdated:date発行日(ソート用)
cs:publisherd:text発行者
cs:maillistcs:addressd:text(maxLength=50000)振り分けアドレスリスト
⚠️ アドレスリストのプロパティは d:text 型・maxLength=50000 で設定してください。上限の50,000文字を超えるとルール実行時にエラーが大量ループし、サーバー全体の負荷が急増します。定期的に不要なアドレスを整理してください。

モデルマネージャーでの設定

1
管理ツール → 「モデルマネージャー」 → bunshoモデル → cs:maillist アスペクトを選択します。
2
「プロパティの作成」 をクリックし、以下の設定で作成します。
項目設定値
名前address
タイトルアドレスリスト
d:text
必須いいえ
複数値いいえ
制約(LENGTH)maxLength50000
3
モデルを 「有効化」 します。
ℹ️ d:text + maxLength=50000 の場合、1件あたり平均30文字のアドレスで約1500件以上登録可能です。

モデルXMLでの設定(直接編集する場合)

bunsho_model.xml(cs:maillist アスペクト部分)
<aspect name="cs:maillist">
  <title>メール一覧</title>
  <properties>
    <property name="cs:address">
      <title>アドレスリスト</title>
      <type>d:text</type>
      <mandatory>false</mandatory>
      <multiple>false</multiple>
      <constraints>
        <constraint name="cs:ADDRESS_LENGTH" type="LENGTH">
          <parameter name="maxLength">
            <value>50000</value>
          </parameter>
          <parameter name="minLength">
            <value>0</value>
          </parameter>
        </constraint>
      </constraints>
    </property>
  </properties>
</aspect>

振り分け先フォルダへのアスペクト設定

各振り分け先フォルダに cs:maillist アスペクトを適用する必要があります。適用されていない場合、cs:address プロパティが利用できず振り分けが機能しません。

1
振り分け先フォルダ(例:取引・情報・その他 など)を右クリック → 「アスペクトの管理」 を選択します。振り分け先フォルダに cs:maillist アスペクトを適用する必要があります。適用されていない場合、cs:address プロパティが利用できず振り分けが機能しません。
2
「使用可能なアスペクト」から cs:maillist(メール一覧) を選択し、「追加」 をクリックします。
3
「変更を適用」 をクリックして保存します。振り分け先フォルダ全てに同様の手順を繰り返します。
ℹ️ アスペクト適用後、フォルダの「プロパティを編集」画面に cs:address(アドレスリスト)フィールドが表示されます。手動振り分け時は mailSortAdd.js が自動でアドレスを追記します。
ℹ️ モデルを無効化するには、アスペクトが適用されている全ノードからアスペクトを除去してから行う必要があります。REST API(/alfresco/api/-default-/public/search/versions/1/search)でノードを検索し、一括除去します。

9. Alfresco Share の設定(メールエイリアス)

メール受信先フォルダに Eメールエイリアスを設定します。このエイリアスに届いたメールが該当フォルダに格納されます。

① アスペクトの管理 — Eメールエイリアスを追加

1
Alfresco Share にログインし、メール受信先フォルダ(例:Shared/mail)に移動します。
2
フォルダを右クリック(またはアクションメニュー)→ 「アスペクトの管理」 を選択します。
3
「使用可能なアスペクト」から 「Eメールエイリアス(emailserver:aliasable)」 を選択し、「追加」 ボタンをクリックします。
4
「変更を適用」 をクリックして保存します。
ℹ️ 「Eメールエイリアス」アスペクトが追加されると、プロパティ編集画面に Eメールエイリアス フィールドが表示されます。

② プロパティの編集 — Eメールエイリアスを設定

1
フォルダを右クリック(またはアクションメニュー)→ 「プロパティを編集」 を選択します。
2
「Eメールエイリアス」 フィールドに送信先の名前を入力します。
例:mail と入力すると、mail@alfresco.example.com 宛のメールがこのフォルダに格納されます。
3
「保存」 をクリックします。
⚠️ Eメールエイリアスは alfresco-global.propertiesemail.server.domain と組み合わせてメールアドレスになります。postfix の relayhost に設定した宛先と一致させてください。

設定値テーブル

設定箇所設定値(例)メールアドレス
Eメールエイリアス mail mail@alfresco.example.com
email.server.domain alfresco.example.com
postfix relayhost [alfresco.example.com]:1025 Alfresco SMTPポートへ中継

10. spamフォルダの定期学習・自動整理

件名に ***SPAM*** が付いたメールを専用フォルダへ振り分け、定期的に SpamAssassin のベイジアンフィルタへ学習させたうえで、学習済みメールをゴミ箱経由で自動整理する仕組みです。cs:address の容量超過(上限50,000文字)を未然に防ぐ目的も兼ねています。

SPAM件名のメール受信
spamフォルダへ自動振り分け
週次cron実行
sa-learn学習
cs:addressクリア+ゴミ箱移動

spamフォルダの準備

  • Shared/mail 配下に spam フォルダを作成
  • フォルダに cs:maillist アスペクトを付与(cs:address プロパティが使えるようになる)

mailSort.js — SPAM件名メールの振り分け先を変更

件名に SPAM を含むメールは、他の振り分け条件より先に判定し、spam フォルダへ直接移動します。

mailSort.js(抜粋)
// 件名にSPAMを含む場合はspamフォルダへ振り分け
var fileName = document.properties['cm:name'];
if (fileName.indexOf("SPAM") != -1) {
  var dest = document.parent.childByNamePath('spam');
  document.move(dest);
}
else {
  // 以降、通常の振り分け先アドレス判定処理
  ...
}
ℹ️ 件名のSPAM判定は spamc-wrapper.sh が付与する ***SPAM*** 表記、または送信元メールサーバー側のSpamAssassinが付与した表記の両方を拾えます。

clearAndDeleteSpam.js — 学習後のクリーンアップ

spamフォルダの cs:address をクリアし、配下のメールフォルダを ゴミ箱(アーカイブ)経由で削除します。remove()はAlfrescoの標準アーカイブストアへ移動するだけのため、誤判定があった場合は一定期間内であれば復元可能です。

clearAndDeleteSpam.js
var targetFolder = companyhome.childByNamePath('Shared/mail/spam');
var deletedCount = 0;
 
// cs:addressをクリア
var aspects = targetFolder.getAspects();
for (var i = 0; i < aspects.length; i++) {
  if (String(aspects[i]) == '{独自名前空間}maillist') {
    targetFolder.properties['cs:address'] = null;
    targetFolder.save();
    break;
  }
}
 
// 配下のメールフォルダをゴミ箱へ移動
var children = targetFolder.children;
for (var j = 0; j < children.length; j++) {
  if (children[j].isContainer) {
    children[j].remove();
    deletedCount++;
  }
}
 
logger.log('spamフォルダ整理完了(ゴミ箱へ移動): ' + deletedCount + '件');

spam-learn-and-clear.sh — 学習・整理を一括実行するシェルスクリプト

spamフォルダ内のメール本体をエクスポートし、sa-learn --spam で学習させたうえで、上記スクリプトを呼び出してクリーンアップします。

/usr/local/bin/spam-learn-and-clear.sh
#!/bin/bash
ALFRESCO_USER="admin"
ALFRESCO_PASS="xxxxxxxx"
ALFRESCO_HOST="http://localhost:8080"
LOGFILE="/var/log/spam-learn.log"
EXPORT_DIR="/tmp/spam_learn_export"
SPAM_FOLDER_ID="spamフォルダのノードID"
CLEAR_SCRIPT_ID="clearAndDeleteSpam.jsのノードID"
 
mkdir -p "$EXPORT_DIR"
rm -rf "${EXPORT_DIR:?}"/*
 
# ① spamフォルダ直下のメールフォルダ一覧を取得
MAIL_NODES=$(curl -s -u "$ALFRESCO_USER:$ALFRESCO_PASS" \
  "$ALFRESCO_HOST/alfresco/api/-default-/public/alfresco/versions/1/nodes/$SPAM_FOLDER_ID/children?maxItems=1000&where=(isFolder=true)" \
  | python3 -c "...各フォルダIDを抽出...")
 
# ② 各メールフォルダ内のメール本体をダウンロード
for FOLDER_ID in $MAIL_NODES; do
  curl -s -u "$ALFRESCO_USER:$ALFRESCO_PASS" \
    "$ALFRESCO_HOST/.../nodes/$DOC_ID/content" \
    -o "$EXPORT_DIR/mail_${COUNT}.eml"
done
 
# ③ sa-learnで一括学習
sa-learn --spam "$EXPORT_DIR"/*.eml >> "$LOGFILE" 2>&1
 
# ④ cs:addressクリア+メールフォルダをゴミ箱へ(REST経由でAlfresco JS実行)
curl -s -u "$ALFRESCO_USER:$ALFRESCO_PASS" \
  -X POST -H "Content-Type: application/json" \
  "$ALFRESCO_HOST/alfresco/s/api/actionQueue?async=false" \
  -d "{\"actionedUponNode\":\"workspace://SpacesStore/$SPAM_FOLDER_ID\", ...}"
 
# ⑤ エクスポート用一時ファイルを削除
rm -rf "${EXPORT_DIR:?}"/*

cron登録

terminal
$ crontab -e
$ # 毎週月曜3:00に実行(業務影響の少ない深夜帯を推奨)
$ 0 3 * * 1 /usr/local/bin/spam-learn-and-clear.sh
⚠️ cronはroot権限・一般ユーザー権限のどちらで登録したか必ず把握しておく。sudo crontab -ecrontab -eは別ファイルとして管理されるため、既存のgetmail設定と混在させる場合は同じ実行ユーザーに揃えるのが安全です。

運用上の注意:大量削除によるサーバー負荷

spamフォルダのノード削除処理は、Alfresco内部でレンディション再生成・検索インデックス更新イベントを発行します。蓄積件数が多い状態で一括削除を実行すると、検索サービス(Solr)のメモリ使用量が一時的に急増し、サーバー全体の応答が著しく低下することがあります。

対策内容
実行時間帯業務影響の少ない深夜帯にcronを設定する
事前テストspamメールが少量たまった状態で一度手動実行し、所要時間・負荷を確認してから自動化する
異常時の対処応答が著しく遅い場合は検索サービスを再起動するとメモリが解放される場合がある
ℹ️ 検索サービスのプロセスメモリ(RSS)がヒープ上限設定を大きく超えて肥大化していないか、定期的に確認することを推奨します。

11. トラブルシューティング

添付ファイルのMIMEタイプ誤設定(PDF・Excel・Wordが表示されない)

  • 原因:メール取り込み時に添付ファイルのMIMEタイプが text/html に誤設定される
  • 新規メール:修正版 mailRename.js で自動的に正しいMIMEタイプが設定される
  • 既存ファイル:以下の fixMime.js をData Dictionary/Scriptsに登録してREST API経由で実行
fixMime.js(既存ファイルの一括修正)
var mimeMap = {
  'pdf' : 'application/pdf',
  'xlsx' : 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
  'xls' : 'application/vnd.ms-excel',
  'docx' : 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  'doc' : 'application/msword',
  'pptx' : 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
  'ppt' : 'application/vnd.ms-powerpoint',
  'csv' : 'text/csv',
  'zip' : 'application/zip'
};
var count = 0;
var targetFolder = companyhome.childByNamePath('Shared/mail');
function fixMime(node) {
  if (node.isDocument) {
    var name = node.properties['cm:name'];
    if (name != null) {
      var lowerName = new String(name).toLowerCase();
      var dotPos = lowerName.lastIndexOf('.');
      var ext = (dotPos >= 0) ? lowerName.substring(dotPos + 1) : '';
      var correct = mimeMap[ext];
      if (correct != null && node.mimetype !== correct) {
        node.mimetype = correct;
        node.save();
        count++;
      }
    }
  }
  if (node.isContainer) {
    for each (var child in node.children) { fixMime(child); }
  }
}
fixMime(targetFolder);
count;

fixMime.js の実行方法(REST API経由)

terminal
$ # 対象フォルダのIDを取得
$ FOLDER_ID=$(curl -s -u admin:パスワード "http://localhost:8080/alfresco/api/-default-/public/alfresco/versions/1/nodes/-root-?relativePath=Shared/mail/%E5%AF%BE%E8%B1%A1%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80" | python3 -c "import sys,json; d=json.load(sys.stdin); print(d['entry']['id'])")
$ # スクリプトを実行
$ curl -s -u admin:パスワード -X POST -H "Content-Type: application/json" "http://localhost:8080/alfresco/s/api/actionQueue?async=false" -d "{\"actionedUponNode\": \"workspace://SpacesStore/$FOLDER_ID\", \"actionDefinitionName\": \"script\", \"parameterValues\": {\"script-ref\": \"workspace://SpacesStore/fixMime.jsのノードID\"}}"

メールループ(too many hops)

🚨 postfix の content_filter = spamassassin を設定するとメールループが発生します。必ずコメントアウトしてください。

振り分けアドレス上限超過

  • 原因:cs:addressd:text 型・最大50,000文字)の容量超過
  • 症状:ルール実行のたびに IntegrityException: String length is not in range [0; 50,000] エラーが大量ループし、サーバー全体の応答が著しく低下する
  • 対処:対象フォルダの cs:address を REST API で null にクリアし、必要なアドレスのみ再登録する
  • 予防:spamフォルダの定期学習・自動整理(10章参照)を設定してアドレスを定期的に整理する

ログ確認コマンド

terminal
$ sudo tail -50 /var/log/mail.log | grep -E "status=|error|bounce"
$ cat /tmp/spamc-wrapper.log | tail -30
$ sudo tail -100 /var/log/alfresco/share.log | grep -i error
$ cat /var/log/getmail.log | tail -30

設定確認チェックリスト

  • postfix の content_filter がコメントアウトされている
  • spamc-wrapper.sh に実行権限がある(chmod +x
  • getmailrc の destination が spamc-wrapper.sh を参照している
  • SpamAssassin(spamd)が起動している
  • 振り分けフォルダに cs:maillist アスペクトが適用されている
  • share-config-custom.xml の XML 構文エラーがない(xmllint --noout で確認)
正常に設定できると、受信メールが自動的にスパム判定・振り分けされてAlfrescoに格納されます。

Alfresco Community 26.1 / Ubuntu 24.04 / Ansible インストール環境での設定例です。