-->

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=xxxxxx.local  # ドメインを指定
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 = xxxxxx.example.com
mydomain = example.com
inet_interfaces = localhost
relayhost = [mail.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 = xxxx@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/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 MAILER-DAEMON@*
 
# ホワイトリスト
whitelist_from *@example.com
whitelist_from *@amazon.co.jp
スコア対応
5.0 以上スパム判定(件名に ***SPAM*** 追加)
10.0 以上破棄(Alfresco に配送しない)
5.0 未満正常メール(Alfresco へ配送)

6. spamc-wrapper スクリプト

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

⚠️ postfix の content_filter = spamassassin を設定するとメールループが発生します。必ずコメントアウトし、getmailrc からラッパースクリプトを直接呼び出す方式を採用してください。
/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"
 
# 最初のX-Spam-Statusのスコアのみ取得
SPAM_FLAG=$(grep "X-Spam-Flag:" "$TMPFILE" | head -1 | awk '{print $2}')
SPAM_SCORE=$(grep "X-Spam-Status:" "$TMPFILE" | head -1 | grep -oP 'score=\K[0-9.]+')
echo "flag: $SPAM_FLAG score: $SPAM_SCORE" >> /tmp/spamc-wrapper.log
 
# スコア10以上は破棄
if [ -n "$SPAM_SCORE" ]; then
  SCORE_INT=$(echo "$SPAM_SCORE" | cut -d. -f1)
  if [ "$SCORE_INT" -ge 10 ]; then
    echo "DISCARDED: $1 score=$SPAM_SCORE" >> /tmp/spamc-wrapper.log
    rm -f "$TMPFILE"
    exit 0
  fi
fi
 
# 10未満はAlfrescoへ配送
/usr/sbin/sendmail -oi -f "$1" mail@xxxxxx.local < "$TMPFILE"
rm -f "$TMPFILE"
terminal
$ sudo chmod +x /usr/local/bin/spamc-wrapper.sh

7. Alfresco スクリプト群

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

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

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

同名メールの重複を防ぐため送信日時を付加し、URLエンコードされた記号を全角に置換します。HTMLメールの場合はMIMEタイプをtext/htmlに変更します。

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 = '';
}
 
// HTMLメールの場合、MIMEタイプを変更
var mailContent = document.content;
if ((mailContent.match(/(<([^>]+)>)/gi) || []).length > 5) {
  document.mimetype = 'text/html';
}
 
// URLエンコード文字を全角に置換
var fullName = document.properties['cm:name'];
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();

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.2)

mailSort.js
// スパムメールは"その他"へ振り分け
var fileName = document.properties['cm:name'];
if (fileName.indexOf("SPAM") != -1) {
  var dest = document.parent.childByNamePath('その他');
  document.move(dest);
} else {
  // nullガード付きgetAdd関数
  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, '|'));
  }
  // 振り分け処理
  var mailFrom = document.properties['cm:originator'];
  if (mailFrom != null) {
    if (getAdd('取引').test(mailFrom)) { document.move(dest); }
    else if (getAdd('情報').test(mailFrom)) { document.move(dest); }
    else if (getAdd('その他').test(mailFrom)) { document.move(dest); }    
  }
}

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 で設定してください。d:mltext 型はロケール情報が各行に付加されるため、実質的に保存できるアドレス数が大幅に減少します(約200件 → 約30件)。

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

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@xxxxxx.local 宛のメールがこのフォルダに格納されます。
3
「保存」 をクリックします。
⚠️ Eメールエイリアスは alfresco-global.propertiesemail.server.domain と組み合わせてメールアドレスになります。postfix の relayhost に設定した宛先と一致させてください。

設定値テーブル

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

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

メールループ(too many hops)

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

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

  • 原因:d:text 型プロパティの文字数制限
  • 対策:d:mltext 型の cs:addresslong に移行し、cs:maillist アスペクトを振り分けフォルダに適用する

ログ確認コマンド

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 インストール環境での設定例です。

環境により設定が異なる場合があります。機密情報は適宜ぼかしてください。